为什么字节提升为枚举?

Mag*_*gus 4 c# enums

在使用具有多个采用不同数据类型但没有枚举的重载的外部 API 时,我决定创建一个方便的方法来为枚举提供更多的类型安全性,最终得到如下结果:

namespace TestEnumPromotion
{
    enum Values
    {
        Value0,
        Value1,
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Prints int
            Overloaded(0);

            // Prints Values
            Overloaded(Values.Value0);

            // Does not compile! :-/
            Overloaded((byte) 0);

            // Prints int
            byte b = 0;
            Overloaded(b);
        }

        static void Overloaded(int i)
        {
            Console.WriteLine("int");
        }

        static void Overloaded(Values i)
        {
            Console.WriteLine("Values");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但我很惊讶地发现代码无法编译,因为Overloaded((byte) 0)

以下方法或属性之间的调用不明确:“Program.Overloaded(int)”和“Program.Overloaded(Values)”

byte不能自动提升为Values,即Values v = (byte)b无法编译,因为:

无法将类型“byte”隐式转换为“TestEnumPromotion.Values”。

所以唯一可能的重载应该是 int,对吗?

我认为枚举可能只是语法糖,编译器会生成接收 int 的方法,但通过 ILDASM 查看 IL 表明实际上创建了一个采用枚举的方法。

.method private hidebysig static void  Overloaded(valuetype TestEnumPromotion.Values i) cil managed
{
    // Code size       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "Values"
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
} // end of method Program::Overloaded
Run Code Online (Sandbox Code Playgroud)

怎么了?

InB*_*een 5

这是语言中一个奇怪的小规则的结果:文字0可以隐式转换为任何enum.

更新:根据评论和链接源,编译器实际上并不遵循规范。编译器允许隐式转换任何零常量,而不仅仅是文字零。您可以在此处阅读有关此问题的更多信息。

这不会编译:

Values someValue = 1; //can not implicitly convert `int` to...
Run Code Online (Sandbox Code Playgroud)

但有趣的是,这将:

Values someValue = 0;
Run Code Online (Sandbox Code Playgroud)

在您的情况下,因为(byte)0(常量零) 可以隐式转换为Valuesand int,所以编译器无法选择最佳重载,并且无法解析调用。如果您将代码更改为(byte)1或任何其他文字值,它将可以正常编译。

值得一提的是,之所以Overloaded(0)有效,只是因为编译器找到了完全匹配的结果;不需要隐式演员表,因此Overloaded(int i)毫无争议地获胜。

引用 c# 4.0 规范:

1.10 (...) 任何枚举类型的默认值都是转换为枚举类型的整数值零。在变量自动初始化为默认值的情况下,这是赋予枚举类型变量的值。为了轻松获得枚举类型的默认值,文字 0 隐式转换为任何枚举类型。(...)

  • [找到了](/sf/answers/996680051/)!像往常一样,埃里克·利珀特来救援。该标准在谈到“字面‘0’”时是在撒谎,事实上任何*常量*“0”都是转换的候选者。将其与重载决议结合起来,鲍勃就是你的叔叔。 (4认同)