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

Mic*_*l B 7 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.
Run Code Online (Sandbox Code Playgroud)

2件事::

  1. 为什么我可以拆箱StringComparison?我想这是因为它的底层类型是,Int32但我仍然觉得它很奇怪.
  2. 为什么nullableEnum值为null?

据我所知,唯一有效的拆箱是从盒装值类型到它的类型或可空类型.如果int可以取消装箱Enum,那么为什么不能同样适用于可空值?同样,如果不是5我装盒StringComparison.OrdinalIgnoreCase,那nullableInt将是null,但nullableEnum不会.

ste*_*son 3

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

如果源操作数为 null,则拆箱到可为 null 类型会生成可为 null 类型的 null 值,否则会生成将对象实例拆箱为可为 null 类型的基础类型的包装结果。

也就是说,如果拆箱到 StringComparison 有效,那么拆箱到 Nullable<StringComparison> 也应该有效。目前尚不清楚两者是否都应该有效或者都应该失败。规范说

为了在运行时成功进行到给定非空值类型的拆箱转换,源操作数的值必须是对该非空值类型的装箱值的引用。

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

  • 回复:运行时中的错误:我不会说这是运行时中的*错误*;相反,在某些情况下,运行时比 C# 规范要求的更宽松。只有付出过高的代价,我们才能将 C# 实现的行为限制为规范的严格实现,而没有任何实际收益。 (2认同)
  • 回复:“兼容”类型:是的,这是规范中的一点挥手。CLR 规则略有不一致。例如,有趣的是,尽管 int 和 uint 在 CLR 中出于数组协方差的目的被视为兼容类型,但出于拆箱的目的,它们在 CLR 中并不被视为兼容类型,尽管 int 和 enum 是兼容的。 (2认同)