I have a method that should return a nullable reference type or a nullable value type:
private static T? FooValueOrReferenceType<T>(string input)
{
return null;
// the code above show this error
// Cannot convert null to type parameter 'T' because it could be
// a non-nullable value type. Consider using 'default(T)' instead.
}
I don't understand why I cant return null, since I have enabled nullable value types in the project
I know that adding constraint where T : struct, class
can resolve the problem, but I want to understand why.
I noticed that this method signature:
private static T? FooValueType<T>(string input) where T : struct
compiled to:
private static Nullable<T> FooValueType<T>([System.Runtime.CompilerServices.Nullable(1)] string input) where T : struct
and this:
private static T? FooReferenceType<T>(string input) where T : class
compiles to:
private static T FooReferenceType<T>(string input) where T : class
What's the reason behind all this?
There is some question similar to this one, but the answers are not clear for a noob like me.
CodePudding user response:
Ultimately, nullability means two fundamentally different things for reference-types and value-types. For value-types, T?
means Nullable<T>
- a wrapper layer around a T
, with some compiler voodoo - and for reference-types, T?
means simply T
, but with some additional compiler context (and attributes added, to convey that intent). There is simply no way in IL of expressing these two things at the same time, and Nullable<T>
and T
cannot be used interchangeably in IL (even if C# makes it look like you can). Ultimately, "you just can't, IL doesn't work that way".
Your two experiments into the : class
and : struct
show these two incompatible variants nicely.