671

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?

4
  • Would nullable reference types (in C# 8) be the better solution to this now? learn.microsoft.com/en-us/dotnet/csharp/nullable-references Returning null regardless of whether T is Object or int or char. Commented May 23, 2020 at 16:35
  • Too bad that T? in the signature doesn't work. @Alexander-ReinstateMonica I've read the article but couldn't see a way to return null regardless of reference or value type. Commented Oct 9, 2020 at 8:03
  • 1
    @mireazma That's way too little information for me to be able to help. You should open a new question. Commented Oct 9, 2020 at 14:03
  • The main problem I see is that you try to use null as indication that something is wrong there. I would propose to throw an exception instead. That's why exceptions exist and you can ommit wirting if (... != null) everywhere. Commented Feb 25, 2022 at 13:48

13 Answers 13

1169

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.
Sign up to request clarification or add additional context in comments.

8 Comments

What if my return type is an enum not a class? I can't specify T : enum :(
In .NET an enum is a very thin (and rather leaky) wrapper around an integer type. The convention is to use zero for your "default" enum value.
I think the problem with this is that if you're using this generic method to say, convert a Database object from DbNull to Int and it returns default(T) where T is an int, it'll return 0. If this number is actually meaningful, then you'd be passing around bad data in cases where that field was null. Or a better example would be a DateTime. If the field was something like "DateClosed" and it was returned as null because and account is still open, it would actually default(DateTime) to 1/1/0000, implying that the account was closed before computers were invented.
@Sinaesthetic: So you'd convert to Nullable<int> or Nullable<DateTime> instead. If you use a non-nullable type and need to represent a null value, you're just asking for trouble.
The challenge is to do something like the following in a generic method if (Nullable.GetUnderlyingType(typeof(T)) != null) { return Task.FromResult<T?>(new Nullable<T>()); } else { return Task.FromResult<T?>(null); }
I agree, I just wanted to bring it up. I think what I've been doing is more like MyMethod<T>(); to assume it is a non nullable type and MyMethod<T?>(); to assume it is a nullable type. So in my scenarios, I could use a temp variable to catch a null and go from there.
|
110
return default(T);

3 Comments

Damn it, I would've saved a lot of time had I known about this keyword - thanks Ricardo!
I'm surprised this hasn't gotten more up votes as the 'default' keyword is a more comprehensive solution, allowing the use of non-reference types in conjunction with numeric types and structs. While the accepted answer solves the problem (and indeed is helpful), it better answers how to restrict return type to nullable/reference types.
49

You can just adjust your constraints:

where T : class

Then returning null is allowed.

3 Comments

Thanks. I cannot choose 2 answers as the accepted solution, so I choose John Skeet's cause his answer has two solutions.
@Migol it depends on your requirements. Maybe their project does require it be IDisposable. Yes, most of the time it doesn't have to be. System.String doesn't implement IDisposable, for example. The answerer should have clarified that, but that doesn't make the answer wrong. :)
@Migol I have no clue why I had IDisposable in there. Removed.
18

Below are the two option you can use

return default(T);

or

where T : class, IThing
 return null;

Comments

15

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()

1 Comment

Thanks. I cannot choose 2 answers as the accepted solution, so I choose John Skeet's cause his answer has two solutions.
15
  1. If you have object then need to typecast

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

    return default(T);
    

1 Comment

Hi user725388, please verify the first option
8

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.

1 Comment

If both constraints are to the same type, you mention the type once and use a comma, like where T : class, IList. If you have constraints to different types, you repeat the token where, as in where TFoo : class where TBar : IList.
6

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

return default;

It returns the same as return default(T);

Comments

5

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;
}

Comments

3

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".

Comments

3

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);
}

1 Comment

Since C# 7.3 (May 2018), you can improve the constraint to where TEnum : struct, Enum. This ensures that a caller does not accidentally supply a value type that is not an enum (such as an int or a DateTime).
3

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;}}

5 Comments

Did you try this code? Only return default(T); will work.
@E.Shcherbo nope it work. Try it on fiddle.
Okay, I didn't notice in your answer that your IThing is the class so your method knows that T is the class, but I'm sure that the author of the question means that IThing is an interface (what the I prefix is saying about) .
@E.Shcherbo I have to apologize. You have right. Unfortunately question is not very verbose. Therefore for lazy people as me is not very feasible to achieve same conditions. :D
no worries, despite the fact that your answer was about other concept (class vs interface) I still think that it was good. It showed the important point how the behaviour of a generic method differs when a type argument is known to be a class or an interface and also emphasised the fact that where T : IThing is also fine with value types.
1

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
}

1 Comment

Downside: this would require the caller of the method to cast the returned object (in non-null case), which implies boxing -> less performance. Am I right?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.