How can I return NULL from a generic method in C#?

C#Generics

C# Problem Overview


I have a generic method with this (dummy) code (yes I'm aware IList has predicates, but my code is not using IList but some other collection, anyway this is irrelevant for the question...)

    static T FindThing<T>(IList collection, int id) where T : IThing, new()
    {
        foreach T thing in collection
        {
            if (thing.Id == id)
                return thing;
        }
        return null;  // ERROR: Cannot convert null to type parameter 'T' because it could be a value type. Consider using 'default(T)' instead.
    }

This gives me a build error

> "Cannot convert null to type parameter > 'T' because it could be a value type. > Consider using 'default(T)' instead."

Can I avoid this error?

C# Solutions


Solution 1 - C#

Three options:

  • Return default (or default(T) for older versions of C#) which means you'll return null if T is a reference type (or a nullable value type), 0 for int, '\0' for char, etc. (Default values table (C# Reference))

  • If you're happy to restrict T to be a reference type with the where T : class constraint and then return null as normal

  • If you're happy to restrict T to be a non-nullable value type with the where T : struct constraint, then again you can return null as normal from a method with a return value of T? - note that this is not returning a null reference, but the null value of the nullable value type.

Solution 2 - C#

return default(T);

Solution 3 - C#

You can just adjust your constraints:

where T : class

Then returning null is allowed.

Solution 4 - C#

Add the class constraint as the first constraint to your generic type.

static T FindThing<T>(IList collection, int id) where T : class, IThing, new()

Solution 5 - C#

  1. If you have object then need to typecast

     return (T)(object)(employee);
    
  2. if you need to return null.

     return default(T);
    

Solution 6 - C#

Below are the two option you can use

return default(T);

or

where T : class, IThing
 return null;

Solution 7 - C#

Your other option would be to to add this to the end of your declaration:

    where T : class
    where T: IList

That way it will allow you to return null.

Solution 8 - C#

solution of TheSoftwareJedi works,

also you can archive it with using couple of value and nullable types:

static T? FindThing<T>(IList collection, int id) where T : struct, IThing
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;
}

Solution 9 - C#

For completeness sake, it's good to know you could also do this:

return default;

It returns the same as return default(T);

Solution 10 - C#

Because of IThing is interface is not possible to use null. So you have to use default(T) to determine default value for actual type T which is defined before function is called.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        IThing x = new List<Thing>().FindThing(1);
        
    }

}

public static class Ext {
    public static T FindThing<T>(this IList<T> collection, int id) where T : IThing, new()
    {
        foreach (T thing in collection)
        {
            if (thing.Id == id) return (T)thing;
        }
    
        //return null; //not work
        //return (T)null; //not work
        //return null as T; //not work
        return default(T); //work
    }
}

public interface IThing { int Id {get; set;} }
public class Thing : IThing { public int Id {get;set;}}

Solution 11 - C#

Take the recommendation of the error... and either user default(T) or new T.

You will have to add in a comparison in your code to ensure that it was a valid match if you go that route.

Otherwise, potentially consider an output parameter for "match found".

Solution 12 - C#

Here's a working example for Nullable Enum return values:

public static TEnum? ParseOptional<TEnum>(this string value) where TEnum : struct
{
    return value == null ? (TEnum?)null : (TEnum) Enum.Parse(typeof(TEnum), value);
}

Solution 13 - C#

Another alternative to 2 answers presented above. If you change your return type to object, you can return null, while at the same time cast the non-null return.

static object FindThing<T>(IList collection, int id)
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return (T) thing;
    }
    return null;  // allowed now
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionedosoftView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Ricardo VillamilView Answer on Stackoverflow
Solution 3 - C#TheSoftwareJediView Answer on Stackoverflow
Solution 4 - C#MinView Answer on Stackoverflow
Solution 5 - C#user725388View Answer on Stackoverflow
Solution 6 - C#Jaydeep ShilView Answer on Stackoverflow
Solution 7 - C#BFreeView Answer on Stackoverflow
Solution 8 - C#gdbdableView Answer on Stackoverflow
Solution 9 - C#LCIIIView Answer on Stackoverflow
Solution 10 - C#MertuarezView Answer on Stackoverflow
Solution 11 - C#Mitchel SellersView Answer on Stackoverflow
Solution 12 - C#LukeView Answer on Stackoverflow
Solution 13 - C#Jeson MartajayaView Answer on Stackoverflow