C# 7.3枚举约束疑问:为何无法使用可空枚举类型?
Nullable<TResult>? 这问题挺典型的——明明C#7.3已经支持Enum作为泛型约束了,怎么写个TResult?就报错了?咱们一步步拆解。
先看你写的代码:
public static TResult? ToEnum<TResult>(this String value, TResult? defaultValue) where TResult : Enum { return String.IsNullOrEmpty(value)? defaultValue : (TResult?)Enum.Parse(typeof(TResult), value); }
编译器抛出的错误很明确:
Error CS0453 The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable'
问题根源
虽然所有枚举类型本质上都是值类型,但where TResult : Enum这个约束并没有给编译器传递足够的信息:Enum本身是一个抽象引用类型,这个约束只保证TResult是枚举类型(或者Enum基类本身),但编译器无法确定TResult一定是符合Nullable<T>要求的非空值类型(也就是struct)。
换句话说,编译器会纠结:万一有人把Enum本身(引用类型)传给TResult呢?那Nullable<Enum>是不合法的,因为Nullable<T>只接受值类型。
解决方案
根据你使用的C#版本,有两种靠谱的解决方式:
1. C#8.0及以上版本(推荐)
C#8.0开始允许同时使用struct和Enum约束,这样就能明确告诉编译器:TResult是一个值类型的枚举,完全符合Nullable<T>的要求。修改后的代码如下:
public static TResult? ToEnum<TResult>(this string value, TResult? defaultValue) where TResult : struct, Enum { return string.IsNullOrEmpty(value) ? defaultValue : (TResult?)Enum.Parse(typeof(TResult), value); }
2. 仍在使用C#7.3的情况
C#7.3不允许同时叠加struct和Enum约束,那我们可以先用struct约束满足Nullable<T>的要求,然后在方法内部做一个运行时检查,确保TResult确实是枚举类型:
public static TResult? ToEnum<TResult>(this string value, TResult? defaultValue) where TResult : struct { if (!typeof(TResult).IsEnum) throw new ArgumentException("TResult must be an enum type.", nameof(TResult)); return string.IsNullOrEmpty(value) ? defaultValue : (TResult?)Enum.Parse(typeof(TResult), value); }
这样既满足了编译要求,又能在运行时保证类型安全。
内容的提问来源于stack exchange,提问作者Kyrylo Kovalenko

