Search code examples
c#nullable-reference-types

C# language spec for type of a Generic when the type parameter is a struct when using NRT annotations


In this code, the type of new Of<int>().Value is int, not int? even though the field declaration for Value has a ?

Does the C# spec clarify that in this case the type of T? will be a (not-nullable) Value type and not a Nullable Value type? I can't find it.

#nullable enable

void Main()
{
    Console.WriteLine( new Of<int>().Value.GetType() );
}

class Of<T>
{
    public T? Value;

    public Of(T? value) => Value = value;
    public Of() {}

    public Of<T> Create() => new Of<T>(default);
    
}

Solution

  • The C# spec has not been properly updated for many of the new features. There are separate addendums for these.

    Unconstrained type parameters with regards NRT is in the feature spec:

    In C#9, ? annotations can be applied to any type parameter, regardless of constraints.

    Unless a type parameter is explicitly constrained to value types, annotations can only be applied within a #nullable enable context.

    If a type parameter T is substituted with a reference type, then T? represents a nullable instance of that reference type.

    var s1 = new string[0].FirstOrDefault();  // string? s1
    var s2 = new string?[0].FirstOrDefault(); // string? s2
    

    If T is substituted with a value type, then T? represents an instance of T. (my bold)

    var i1 = new int[0].FirstOrDefault();  // int i1
    var i2 = new int?[0].FirstOrDefault(); // int? i2
    

    If T is substituted with an annotated type U?, then T? represents the annotated type U? rather than U??.

    var u1 = new U[0].FirstOrDefault();  // U? u1
    var u2 = new U?[0].FirstOrDefault(); // U? u2
    

    If T is substituted with a type U, then T? represents U?, even within a #nullable disable context.

    #nullable disable
    var u3 = new U[0].FirstOrDefault();  // U? u3