【问题标题】:Why is Byte Promoted to Enum?为什么字节被提升为枚举?
【发布时间】:2018-03-21 18:21:08
【问题描述】:

在使用具有多个重载的外部 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");
        }
    }
}

但我很惊讶地看到代码没有编译,因为Overloaded((byte) 0)

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

但是byte不能自动提升为Values,也就是说Values v = (byte)b不会编译,因为:

无法将类型“字节”隐式转换为“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

发生了什么?

【问题讨论】:

  • 你可以声明基于其他数值类型的枚举(例如enum Values : long),但默认是int。

标签: c# enums


【解决方案1】:

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

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

这不会编译:

Values someValue = 1; //can not implicitly convert `int` to...

但有趣的是,这会:

Values someValue = 0;

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

值得一提的是,Overloaded(0) 起作用的原因仅仅是因为编译器找到了完全匹配;不需要隐式转换,因此Overloaded(int i) 毫无争议地获胜。

引用 c# 4.0 规范:

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

【讨论】:

  • (byte) 0 不是“文字0”,所以这要么不完整,要么是编译器错误。 (我似乎记得将常量转换为特定类型确实很奇怪,编译器比它应该更灵活地处理,但我不记得我在哪里看到的另一个问题。这也可能是极其复杂的规则的结果C# 有重载决议。)
  • Found it!像往常一样,埃里克·利珀特(Eric Lippert)来救援。该标准在谈论“literal 0”时是在撒谎,实际上任何 constant 0 都是转换的候选者。将它与重载决议混合起来,鲍勃就是你的叔叔。
猜你喜欢
  • 1970-01-01
  • 2019-03-24
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 2015-09-10
  • 2013-10-13
  • 1970-01-01
相关资源
最近更新 更多