Why the code below doesn't work?
public T? Method<T>()
{
/*
error CS0403: Cannot convert null to type parameter 'T'
because it could be a non-nullable value type.
Consider using 'default(T)' instead.
*/
return null;
}
CodePudding user response:
The "why" is simple: I can call Method<int?>()
- so T
is int?
and now T?
is int??
which isn't legal, or Method<string>
, nothing that string?
isn't legal (except recently with nullable references although that works quite differently under the hood)
You can fix that by adding where T : struct
, which limits to scenarios that are valid (non-nullable value types)
CodePudding user response:
You have two options:
return
default(T)
- my source is: https://www.c-sharpcorner.com/article/defaultt-in-generics/add a constraint:
where T : class
.
CodePudding user response:
For the sake of backward compatibility, T?
is implemented as a pure compile-time construct. For reference type, it's the same as T
at runtime. For value type, it is translated to Nullable<T>
. The compiler needs to know for sure that T
is a value type at compile time to do the translation. Thus for unconstraint type T
, the compiler can't assume T?
is nullable.
To get the behavior in the OP, the only OOTB way seems to be to overload the method for reference and value types. Unfortunately changing the type constraint is not enough for overload resolution so the name or the parameters would need to be different as well.
public static T? Method<T>() where T : struct
{
return null;
}
public static T Method<T>(int placeholder = 0) where T : class
{
return null;
}
Depending on what you're trying to do, Chenga's solutions are likely easier to work with, but this will work if you absolutely need it to return null with a non-nullable type constraint. If you're concerned about default
being a non-null value you could also implement an Optional
type such as the one in the question linked and return that instead of T
.