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

发布于 2024-09-28 19:26:52 字数 700 浏览 0 评论 0原文

考虑以下几点::

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?

据我了解,唯一有效的拆箱是从装箱值类型到它的类型或可为空类型。如果 int 可以取消装箱为 Enum,那么为什么对于可为 null 的值则不成立呢?同样,如果我装箱的不是 5,而是 StringComparison.OrdinalIgnoreCase,则 nullableInt 将为 null,但 nullableEnum 不会。

Consider the following::

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 things::

  1. Why can I unbox to StringComparison? I guess this is because it's underlying type is Int32 but I still find it odd.
  2. Why does nullableEnum have a value of null?

As I understand the only valid unboxing is from a boxed value type is to it's type or to a nullable type. If int can unbox to Enum, then why doesn't the same hold true for the nullable values? Similarly, if Instead of 5 I boxed StringComparison.OrdinalIgnoreCase, it would be that nullableInt would be null, but nullableEnum would not be.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坠似风落 2024-10-05 19:26:52

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

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

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

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

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

Strictly speaking I think it's a bug in implementation detail of the runtime, since the C# spec says

Unboxing to a nullable-type produces the null value of the nullable-type if the source operand is null, or the wrapped result of unboxing the object instance to the underlying type of the nullable-type otherwise.

That is, if unboxing to StringComparison works, then unboxing to Nullable<StringComparison> should work too. It's a little unclear whether both should work or both should fail. The spec says that

For an unboxing conversion to a given non-nullable-value-type to succeed at run-time, the value of the source operand must be a reference to a boxed value of that non-nullable-value-type.

You have to decide whether a boxed int is a considered to be a boxed value of type StringComparison because the underlying type of StringComparison is int. The spec goes on to say that an InvalidCastException is thrown if the box contains an "incompatible object". An int is certainly "compatible" with StringComparison, because you can safely copy the four bytes from the heap into your StringComparison variable.

风吹雨成花 2024-10-05 19:26:52

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

        StringComparison? nullableEnum = (StringComparison?)nullableInt;

When you cast enum or integer to object, it still holds type information. So box is StringComparison will return false. But it is allowed to cast any enum or int to any enum, so explicit cast (StringComparison)box works. It is a special case for enums. Nullable<T>, on the other hand, is just a usual class, T is not handled in any specific way when you cast or check type. This is why this code will throw exception.

        StringComparison? nullableEnum = (StringComparison?)nullableInt;
千と千尋 2024-10-05 19:26:52

1)是的,枚举的基础类型是 int,这就是它以这种方式工作的原因。更。您可以执行以下操作:

枚举 MyEnum
{
    一=1,
    二 = 2,
}

整数 i = 3;
MyEnum myEnum = (MyEnum)i; // 这毫无例外地有效。

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

1) Yes, underlying type of enum is int and that's why it works in this way. Even more. You can do following:

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

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

2) Because StringComparison? is actually Nullable<StringComparison> which is different type. And as operator only checks if the object is of the same type as specified in as operator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文