使用方法重载和枚举的奇怪(可能是错误的?)C#编译器行为

Grz*_*Kyc 11 c# compiler-construction enums compiler-errors

今天我发现了一个非常奇怪的C#函数重载行为.当我有一个方法有2个重载,一个接受对象,另一个接受任何类型的枚举时,会出现问题.当我将0作为参数传递时,将调用该方法的Enum版本.当我使用任何其他整数值时,将调用Object版本.我知道这可以通过使用显式转换来轻松修复,但我想知道为什么编译器会以这种方式运行.这是一个错误还是我不知道的一些奇怪的语言规则?

下面的代码解释了问题(使用运行时2.0.50727检查)

感谢您对此的任何帮助,Grzegorz Kyc

class Program
{
    enum Bar
    {
        Value1,
        Value2,
        Value3
    }

    static void Main(string[] args)
    {
        Foo(0);
        Foo(1);
        Console.ReadLine();
    }

    static void Foo(object a)
    {
        Console.WriteLine("object");
    }

    static void Foo(Bar a)
    {
        Console.WriteLine("enum");
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 13

可能是您不知道存在从0 的常量1到任何枚举的隐式转换:

Bar x = 0; // Implicit conversion
Run Code Online (Sandbox Code Playgroud)

现在,从0到0 Bar的转换比从0到0的转换更具体object,这就是使用Foo(Bar)过载的原因.

这清楚了吗?


1 Microsoft C#编译器实际上存在一个错误,它允许它为任何零常量,而不仅仅是一个整数:

const decimal DecimalZero = 0.0m;

...
Bar x = DecimalZero;
Run Code Online (Sandbox Code Playgroud)

它不太可能被修复,因为它可能会破坏现有的工作代码.我相信埃里克利珀有两个博客 的帖子,其进入更多的细节.

C#规范第6.1.3节(C#4规范)对此有这样的说法:

隐式枚举转换允许将decimal-integer-literal 0转换为任何枚举类型和任何可以为其类型为枚举类型可空类型.在后一种情况下,通过转换为基础枚举类型 并包装结果来评估转换(第4.1.10节).

这实际上表明该错误不仅仅是允许错误的类型,而是允许转换任何常量0值而不仅仅是字面值0.

编辑:看起来"常量"部分在C#3编译器中部分引入.以前它是一些不变的值,现在它看起来就像它们一样.

  • 您正在寻找的帖子是http://blogs.msdn.com/b/ericlippert/archive/2006/03/28/the-root-of-all-evil-part-one.aspx和http:// blogs.msdn.com/b/ericlippert/archive/2006/03/29/the-root-of-all-evil-part-two.aspx.在允许编译器使用任何常量零时,我意外地使它使用任何类型的任何常量零,而不仅仅是整数类型.我很遗憾导致这场混乱的所有错误. (4认同)