Let's say I have a struct as follows:
public readonly struct Quantity<T> {
public readonly T value;
public Quantity(T value) {
this.value = value;
}
}
If I then have a method with the following signature:
void Foo(Quantity<string?> quantity) { ... }
Why does the following produce a CS8620
warning, "Argument cannot be used for parameter due to differences in the nullability of reference types."?
Quantity<string> strQuantity = new Quantity<string>("Hello world");
Foo(strQuantity);
Or, rather, how do I avoid the warning? As I understand it, string
and string?
are the same types under the hood - and clearly in this case a Quantity<string>
can be used anywhere a Quantity<string?>
is required. So how do I indicate this to the compiler?
Some thoughts:
new Quantity<string?>(strQuantity.value)
) feels a bit ridiculous, given that the underlying data would be identical, and therefore it's just a waste of time. For the same reason the compiler won't allow an explicit/implicit cast to be written for the Quantity
struct.Quantity
is a class rather than a struct?IQuantity<out T>
, or something? Would that even help?The .NET JIT is pretty good at "unwrapping" structs of a single field. I wouldn't worry too much about creating extra instances of such structs.
ImmutableArray<T>
is a common type with a similar problem, which it solves using the CastUp method.
For the nullable case specifically, you can just use !
to suppress the warning. You can consider wrapping the suppression in a method to make things more clear.
public static ImmutableArray<T?> AsArrayOfNullable<T>(this ImmutableArray<T> input) where T : class => input!;
There's also a csharplang discussion for possibly extending places where variant type parameters are permitted: https://github.com/dotnet/csharplang/issues/3950