虽然使用了一个外部 API,该 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)
:
The call is ambiguous between the following methods or properties: 'Program.Overloaded(int)' and 'Program.Overloaded(Values)'
但是byte
不能自动提升为Values
,即Values v = (byte)b
不会编译,因为:
Cannot implicitly convert type 'byte' to '`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
发生了什么事?
最佳答案
这是语言中一个奇怪的小规则的结果:文字 0
可以隐式转换为任何 enum
。
更新:根据评论和链接的来源,编译器实际上并不遵循规范。编译器允许隐式转换任何零常量,而不仅仅是文字零。您可以阅读有关此问题的更多信息 here .
这不会编译:
Values someValue = 1; //can not implicitly convert `int` to...
但是,有趣的是,这将:
Values someValue = 0;
在您的情况下,因为 (byte)0
(常量零)可以隐式转换为 Values
和 int
,编译器不能选择最佳过载失败无法解决调用。如果您将代码更改为 (byte)1
或任何其他文字值,它会编译得很好。
值得一提的是,Overloaded(0)
起作用的原因仅仅是因为编译器找到了精确匹配;不需要隐式转换,因此 Overloaded(int i)
毫无争议地获胜。
引用 c# 4.0 规范:
1.10 (...) The default value of any enum type is the integral value zero converted to the enum type. In cases where variables are automatically initialized to a default value, this is the value given to variables of enum types. In order for the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type.(...)
关于c# - 为什么 Byte 被提升为 Enum?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49413932/