If I have a type, say, an int, I can make it nullable by adding a question mark to the end of it. For instance, the following code compiles:
int? x = null;
while the following code, with the question mark removed, does not:
int x = null; //throws a build error
My understanding was that I could do this to any type; just add a question mark to the end of it, and I could always assign a null value to it.
However, for some reason, this does not work with generic functions. Consider the following:
T? ReturnNull<T>() => null;
It throws compiler error CS0403:
CS0403: Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using default('T') instead.
What!? If I add the question mark to the name of any type (class or struct), I can assign it a null value and it works fine!
Intriguingly, if I require T to be a class or to be a struct:
T? ReturnNull<T>() where T : class => null;
T? ReturnNull<T>() where T : struct => null;
It works fine. I though I could just workaround the issue by overloading the two above functions (a type may not be both class and struct, right?).
No, I couldn't. I thought wrong. The following throws a build error:
T? ReturnNull<T>() where T : class => null;
T? ReturnNull<T>() where T : struct => null;
CS0128: A local variable or function named 'ReturnNull' is already defined in this scope
WHAT!? I can overload functions by changing the parameters! Why can't I overload functions by changing the type constraints for the generic arguments? Classes and structs don't overlap! EVER!
I'm baffled. I've been very nice to my IDE, not teased it or anything; that can't be the problem. Why isn't this working?
I'm reading this article Constraints on type parameters and Unconstrained type parameter annotations from learn.microsoft.com
These might be the reason why
Which means you need to put explicit constraint to those method like:
About why this code doesn't work
According to Member Overloading - microsoft.com and Generic methods - microsoft.com
which means the two of your
ReturnNullgeneric function are having same signature.Both functions above did not pass any argument and type inference does not work with methods that have no parameters, result in both are having same siganature.
with parameters
If you add parameter of type T, the type inference will apply and make it two different signatures:
without parameters when calling functions
If you really don't want parameters when calling it, you can gave them different type with dummy default value:
and use it likes:
Note: overloading does not work for local function. That means even with different parameter, two local functions with the same name will not compile.