其他分享
首页 > 其他分享> > 隐式转换0到枚举

隐式转换0到枚举

作者:互联网

在C#中,可以将十进制文字0隐式转换为枚举(或其基础类型为枚举的可空值).

C# spec,GitHub上的当前版本

An implicit enumeration conversion
permits the decimal_integer_literal 0 to be converted to any enum_type
and to any nullable_type whose underlying type is an enum_type. In the
latter case the conversion is evaluated by converting to the
underlying enum_type and wrapping the result (Nullable types).

ECMA-334,第11.2.4节隐式枚举转换

An implicit enumeration conversion permits the decimal-integer-literal
0 (or 0L, etc.) to be converted to any enum-type and to any
nullable-value-type whose underlying type is an enum-type. In the
latter case the conversion is evaluated by converting to the
underlying enum-type and wrapping the result (§9.3.11)

基于此,以下所有示例均应合法.此示例来自Eric Lippert的文章The Root Of All Evil, Part One.

enum E
{
  X, Y, Z
}

E e1 = E.X;
E e2 = 0 | E.X;
E e3 = E.X | 0;
E e4 = E.X | 0 | 0;
E e5 = 0 | E.X | 0;

但是,正如Eric所解释的,以下情况应该是非法的:

E e6 = 0 | 0 | E.X;

原因是0 | 0 | E.X等于(0 | 0)| E.X和0 | 0不是文字,而是一个值为0的编译时常量.在以下情况下也是如此:

E e7 = 1 - 1;
E e8 = 2 - 1 - 1 + 0;
E e9 = (0L & 1);

但是,所有这些都可以正常工作.此示例中的e6,e7,e8和e9的值为E.X.

这是为什么?标准中是否有一个(较新的)规范,说明编译时常量为0也可以隐式转换为任何枚举,或者这是编译器在没有完全遵循规范的情况下执行的操作吗?

解决方法:

如您所述,0 | 0 | E.X绑定为(0 | 0)| E.X.

Eric指出,编译器未遵循0 |的规范. 0 | E.X:

After we’ve got a complete parse tree we walk through the parse tree making sure that all the types work out. Unfortunately the initial type binding pass bizarrely enough does arithmetic optimizations. It detects the 0|something and aggressively replaces it with just something , so as far as the compiler is concerned, the sixth case is the same as the second, which is legal. Argh!

埃里克在评论中指出:

but (7-7)|E.X does correctly produce an error

看起来Roslyn在折叠常量方面比本机编译器要聪明一些.他们很可能在这里着眼于效率,而不必担心在极端情况下保留针对错误的行为.

出于相同的原因,现在似乎完全相同的问题似乎适用于7-7或编译器可以在该初始类型绑定过程中将其评估为0的任何其他表达式.

我认为持续折叠发生在here

newValue = FoldNeverOverflowBinaryOperators(kind, valueLeft, valueRight);
if (newValue != null)
{
    return ConstantValue.Create(newValue, resultType);
}

如您所见,这将创建一个新的ConstantValue.因此(0 | 0)| E.X变为0 | E.X,其中第一个0为常数.当编译器折叠到0时| E.X,它不知道0不是原始源中的原义0,而是由编译器生成的常量,因此将其折叠起来就好像您编写了0 |.最初是E.X.

您的其他示例也是如此,我认为这是通过相同的代码完成的. 1-1和其他的一样折叠成常数0.对于任何表达式,编译器在编译时可以将其评估为0,都会发生这种情况.

标签:enums,implicit-conversion,type-conversion,c
来源: https://codeday.me/bug/20191108/2005275.html