Repository navigation
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? |
Replies: 3 comments 9 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 |
|
I'm assuming that none of that--particularly type parameter constraints included in method signatures--is subject to requests for change or enhancement? |
|
In case of Version 2, you can add a parameter as signatures to make it works:
|
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 justTas 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 thestructconstraint theT?type has to refer toTinstead. As it's not possible forintor other value types to benull, the closest you can get isdefaultor0.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β¦