为什么取消装箱枚举会产生奇怪的结果?
考虑以下::
Object box = 5; int @int = (int)box; // int = 5 int? nullableInt = box as int?; // nullableInt = 5; StringComparison @enum = (StringComparison)box; // enum = OrdinalIgnoreCase StringComparison? nullableEnum = box as StringComparison?; // nullableEnum = null.
2件事::
- 为什么我可以拆箱到
StringComparison
? 我想这是因为它的底层类型是Int32
但我仍然发现它很奇怪。 - 为什么
nullableEnum
的值为null?
据我所知,唯一有效的拆箱是从盒装值类型到它的类型或可空类型。 如果int
可以unbox到Enum
,那么为什么对于可空值可以不相同呢? 类似地,如果不是5个盒装的StringComparison.OrdinalIgnoreCase
,那么nullableInt
将为null,但nullableEnum
不会。
严格来说,我认为这是一个 错误 运行时的实现细节 ,因为C#规范说
如果源操作数为空,则取消装入可空类型会产生可空类型的空值,否则会将对象实例的解包装结果解析为可为空类型的基础类型。
也就是说,如果对StringComparison进行拆箱工作,那么取消装箱到Nullable
对于在给定的非可空值类型的取消装箱转换以在运行时成功,源操作数的值必须是对该非可空值类型的装箱值的引用。
您必须确定boxed int是否被认为是StringComparison类型的盒装值,因为StringComparison的基础类型是int。 规范继续说如果该框包含“不兼容的对象”,则抛出InvalidCastException。 int当然与StringComparison“兼容”,因为您可以安全地将堆中的四个字节复制到StringComparison变量中。
将枚举或整数强制转换为对象时,它仍保存类型信息。 所以box is StringComparison
将返回false
。 但是允许将任何枚举或int转换为任何枚举,因此显式转换(StringComparison)box
可以工作。 这是枚举的特例。 另一方面, Nullable
只是一个普通的类,当你强制转换或检查类型时,T不会以任何特定的方式处理。 这就是为什么这段代码会抛出exception。
StringComparison? nullableEnum = (StringComparison?)nullableInt;
1)是的,枚举的基础类型是int,这就是它以这种方式工作的原因。 更。 你可以这样做:
enum MyEnum { One = 1, Two = 2, } int i = 3; MyEnum myEnum = (MyEnum)i; // This works without exceptions.
2)因为StringComparison?
实际上是Nullable
,它是不同的类型。 并且操作符仅检查对象是否与as运算符中指定的类型相同。