Irritation: Necessity of separate struct/class methods for dealing with nullable generics #7902
-
Disclaimer: I come from F# and thus may insufficiently understand the mindset of C#. I'll be humble. IssueFrequently, as I am writing a helper method involving generics and nullability, I find my code failing to compile because it needs a Version 1public static T? GetFirst<T>(List<T> a) => a.Count > 0 ? a[0] : null; // Cannot convert expression type 'null' to return type 'T?' I wish my method to work on either, so I copy and paste the method, then mark one for Version 2public static T? GetFirst<T>(List<T> a) where T : struct => a.Count > 0 ? a[0] : null;
public static T? GetFirst<T>(List<T> a) where T : class => a.Count > 0 ? a[0] : null; But now I have a compiler error: "Member with the same signature is already declared". Since they cannot take the same types, I would have expected these two methods to be interpreted as overloads, but the compiler does not so evaluate them. My usual workaround is to name them differently: Version 3public static T? GetFirstVal<T>(List<T> a) where T : struct => a.Count > 0 ? a[0] : null;
public static T? GetFirstRef<T>(List<T> a) where T : class => a.Count > 0 ? a[0] : null; But this seems quite ugly. Potential solutionsMy usual workaround is to name them differently: public static T? GetFirstVal<T>(List<T> a) where T : struct => a.Count > 0 ? a[0] : null;
public static T? GetFirstRef<T>(List<T> a) where T : class => a.Count > 0 ? a[0] : null; But this is ugly. Optimally C# would simply allow version 1, deducing that my method is valid for either What about version 2? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
These limitations are inherent to .NET, not C#. Part of the confusion comes from the C# syntax for nullable reference types, The second issue is that the runtime does not include generic type parameter constraints as part of the method signature. So it's not possible for two methods with identical signatures to differ only by generic type constraints. C# also does not permit methods to be overloaded based on return type, which might otherwise permit the overloading you are attempting since technically one method would return One way you could resolve this is to return a wrapper type, something like |
Beta Was this translation helpful? Give feedback.
-
I'm assuming that none of that--particularly type parameter constraints included in method signatures--is subject to requests for change or enhancement? |
Beta Was this translation helpful? Give feedback.
These limitations are inherent to .NET, not C#.
Part of the confusion comes from the C# syntax for nullable reference types,
T?
. In that case the actual type is justT
as it is already nullable. But for value types,T?
actually refers to the special wrapper typeNullable<T>
. It's not possible for the signature to vary based on the generic type argument, so without thestruct
constraint theT?
type has to refer toT
instead. As it's not possible forint
or other value types to benull
, the closest you can get isdefault
or0
.The second issue is that the runtime does not include generic type parameter constraints as part of the method signature. So it's not possible for two methods with id…