为什么拆箱枚举会产生奇怪的结果?

时间:2010-10-26 17:45:26

标签: c# enums unboxing

考虑以下内容:

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件事::

  1. 为什么我可以取消收件箱到StringComparison?我想这是因为它的基础类型是Int32,但我仍然觉得它很奇怪。
  2. 为什么nullableEnum的值为null?
  3. 据我所知,唯一有效的拆箱是从盒装值类型到它的类型或可空类型。如果int可以取消装箱到Enum,那么为什么不能对可空值进行同样的操作?同样,如果我将StringComparison.OrdinalIgnoreCase设为nullableInt,而nullableEnum将为空,而不是{{1}}。

3 个答案:

答案 0 :(得分:2)

严格来说,我认为这是运行时 实现细节中的错误,因为C#规范说

  

如果源操作数为null,则取消装入nullable-type会产生nullable-type的null值,否则会将对象实例的解包装结果解析为nullable-type的基础类型。

也就是说,如果取消装配到StringComparison,则取消装箱到Nullable< StringComparison>也应该工作。有两点是否应该有效或两者都失败有点不清楚。规范说

  

对于在给定的非可空值类型的取消装箱转换以在运行时成功,源操作数的值必须是对该非可空值类型的装箱值的引用。

您必须确定boxed int是否被认为是StringComparison类型的盒装值,因为StringComparison的基础类型是int。规范继续说如果该框包含“不兼容的对象”,则抛出InvalidCastException。 int当然与StringComparison“兼容”,因为您可以安全地将堆中的四个字节复制到StringComparison变量中。

答案 1 :(得分:1)

当您将enum或integer强制转换为object时,它仍然保存类型信息。因此box is StringComparison将返回false。但允许将任何枚举或int转换为任何枚举,因此显式转换(StringComparison)box有效。这是枚举的特例。另一方面,Nullable<T>只是一个普通的类,当你强制转换或检查类型时,T不会以任何特定的方式处理。这就是为什么这段代码会抛出异常。

        StringComparison? nullableEnum = (StringComparison?)nullableInt;

答案 2 :(得分:-1)

1)是的,枚举的基础类型是int,这就是它以这种方式工作的原因。更。你可以这样做:

enum MyEnum
{
    One = 1,
    Two = 2,
}

int i = 3;
MyEnum myEnum = (MyEnum)i; // This works without exceptions.

2)因为StringComparison?实际上是Nullable<StringComparison>,它是不同的类型。 as运算符仅检查对象是否与运算符中指定的类型相同。