Search code examples
c#genericsreferencenulldefault

The [default] keyword doesn't work for C# generic type return value?


I'm converting some old C# code to use C# 8, and have encountered this problem:

class MyList<T> : IMyEnumberable<T>
{
    public T GetDefault()
    {
        return default;// a default expression introduces a null value when 'T' is a non-nullable reference type
    }
}

It failed to compile and says

a default expression introduces a null value when 'T' is a non-nullable reference type

I'm not sure what is the problem here - any explanations?


Solution

  • The problem is that someone could do:

    var list = new MyList<string>();
    string d = list.GetDefault();
    

    Because they created a MyList<string>, then T is string, (i.e. a non-nullable string). Therefore because GetDefault() returns a T, this should mean that it returns a non-nullable string.

    However if they call GetDefault(), that will return default(string), which is null. They'll get null when they weren't expecting one!


    You can't prevent someone from creating a MyList<string>: there's no syntax to say "T must only be a nullable type, and must not be a non-nullable type".

    If you constrain T to be a struct or class, you can write:

    class MyList<T> : IMyEnumberable<T> where T : struct // or : class
    {
        public T? GetDefault()
        {
            return default;
        }
    }
    

    Alternatively, you can add a [MaybeNull] to the return type of GetDefault() to say that, even though it returns T (and T may be non-nullable), this method might actually return null.

    (Note that currently this only affects callers of GetDefault(), and not the actual body, so you'll still need the null-suppressing operator !. It looks like this will change soon):

    using System.Diagnostics.CodeAnalysis;
    
    class MyList<T> : IMyEnumberable<T>
    {
        [return: MaybeNull]
        public T GetDefault()
        {
            return default!;
        }
    }
    

    SharpLab.