JHB*_*ius 2 c# generics enums nullable
我编写了一个简单的扩展方法来帮助将字符串解析为可为空的枚举类型。
public static TEnum? ParseNullableEnum<TEnum>(this string? str)
where TEnum : Enum
{
if (str is null)
{
return null;
}
if (!Enum.TryParse(typeof(TEnum), str, ignoreCase: true, out var source))
{
throw new ArgumentOutOfRangeException(nameof(str), str, null);
}
return (TEnum)source;
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,返回类型是TEnum?
,其中TEnum
是Enum
。并且启用了 nullable,因此 null 是一个有效值。但是,我在网上遇到错误return null;
CS0403:无法将 null 转换为类型参数“TEnum”,因为它可能是不可为 null 的值类型。考虑使用 default('TEnum') 代替。
这是VS的bug,还是我做错了什么?我没有转换为TEnum
,输出类型是TEnum?
...对吗?
你要:
public static TEnum? ParseNullableEnum<TEnum>(this string? str)
where TEnum : struct, Enum
Run Code Online (Sandbox Code Playgroud)
您遇到的问题是Enum
约束可以匹配任何特定的枚举类型或Enum
类本身。(Enum
这是一个奇怪的类型:它是所有枚举类型的基本类型,但它本身是一种引用类型。它基本上代表一个装箱枚举类型,即您可以编写Enum foo = condition ? ConsoleColor.Black : ConsoleKey.A;
, 来选择两个随机不同的枚举类型)。
换句话说,有人可以调用:
ParseNullableEnum<Enum>("thing")
Run Code Online (Sandbox Code Playgroud)
添加struct
约束会强制某人实际传递特定的枚举类型,而不是Enum
.
难题的另一部分是,如果泛型类型参数T
不限于class
or struct
,则T?
意味着它T
是“可默认的”而不是“可为空的”。这意味着:
T
是引用类型,T?
则允许null
赋值T
是值类型,T?
并不意味着Nullable<T>
,它只是意味着与 相同T
。这是由于T?
编译器对引用类型和值类型的实现方式不同所致。对于值类型,T?
是 type 的简写Nullable<T>
,但对于引用类型,T?
编译为相同的内容,T
但仅对编译器警告产生影响。编译器不可能发出返回类型为T
whenT
是引用类型,但Nullable<T>
whenT
是值类型的方法。
因此,通过不限制T
引用或值类型,您的返回类型TEnum?
并不意味着Nullable<TEnum>
,它只是意味着TEnum
不同的可为空警告。通过限制TEnum
值类型,编译器可以发出实际返回 的方法Nullable<TEnum>
,因此允许具有值null
。