Troskyvs
Troskyvs

Reputation: 8047

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?

Upvotes: 0

Views: 419

Answers (2)

canton7
canton7

Reputation: 42225

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.

Upvotes: 2

Alex - Tin Le
Alex - Tin Le

Reputation: 2000

You don't put any constraint to your generic T, so basically T can be anything. That's why you got default null.

var test = new MyList<SomeClass>().GetDefault(); // This gives you null
var test2 = new MyList<int>().GetDefault(); // This gives you 0

If you want to force T must be non-nullable, use this.

class MyList<T> where T : struct

Upvotes: 1

Related Questions