Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching nullability of argument and return type's generic type parameters

public readonly struct Foo<T>
{
    // ...
    public T Value { get; }
}

public static Foo<string?> Bar(Foo<string?> foo)
{
    if (foo.Value is null) { /* Something */ }
    else { /* Some other thing */ }
    return foo;
}

public static void Main()
{
    var foo1 = new Foo<string>("s");
    var ret1 = Bar(foo1); // Warns because foo1's type parameter is not nullable

    var foo2 = new Foo<string?>("s");
    var ret2 = Bar(foo2); // Ok because foo2's type parameter is nullable
}
  • Can I write Bar to accept both Foo<string?> and Foo<string>?
  • Can I annotate Bar to specify "what goes in goes out", so the nullability of T of the returning Foo<T> will be the same as the nullability of T of the parameter Foo<T>?
like image 672
Şafak Gür Avatar asked Oct 09 '19 09:10

Şafak Gür


1 Answers

For a Foo<string?> Bar(Foo<string?> foo) method, the type parameter of the accepted foo has no relation to the type parameter of the returned foo. And currently, there is no way to annotate the intended relationship of their nullabilities.

Type parameter T in a generic Foo<T> Bar<T>(Foo<T> foo) method, however, would allow us to share the nullability and we could add a generic type constraint like where T : MyType? in order to use type-specific functionality.

Unfortunately, we can't write where T : string?, because C# does not allow sealed classes to be used as type constraints. This is reasonable as it wouldn`t make sense before - why would we design the method as generic at the first place if there is only one type we can use anyway? Well, with C# 8 and nullable reference types are out in the wild, I think we may have a valid reason now. Maybe the team can lift this restriction as they lifted it for enums.

To answer my own question:

  • There is no attribute to annotate this use case.
  • Generics can be used with type constraints but only with types that are not sealed.

As a side note: Even though C# doesn't let us use sealed types as type constraints, IL does. So if weaving is an option, we can actually add sealed type constraints to generic type parameters. A solution like ExtraConstraints can be extended to provide this functionality.

like image 67
Şafak Gür Avatar answered Oct 22 '22 10:10

Şafak Gür