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

Strange (possibly wrong?) C# compiler behavior with method overloading and enums(带有方法重载和枚举的奇怪(可能是错误的?)C# 编译器行为)

本文介绍了带有方法重载和枚举的奇怪(可能是错误的?)C# 编译器行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

today I discovered a very strange behavior with C# function overloading. The problem occurs when I have a method with 2 overloads, one accepting Object and the other accepting Enum of any type. When I pass 0 as parameter, the Enum version of the method is called. When I use any other integer value, the Object version is called. I know this can be easilly fixed by using explicit casting, but I want to know why the compiler behaves that way. Is this a bug or just some strange language rule I don't know about?

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

The code below explains the problem (checked with runtime 2.0.50727)

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

Thanks for any help on this, 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");
    }
}

推荐答案

你可能不知道有一个从 0 的常量1 到任何枚举的隐式转换:

It may be that you're not aware that there's an implicit conversion from a constant1 of 0 to any enum:

Bar x = 0; // Implicit conversion

现在,从 0 到 Bar 的转换比从 0 到 object 的转换更具体,这就是为什么 Foo(Bar) 使用了重载.

Now, the conversion from 0 to Bar is more specific than the conversion from 0 to object, which is why the Foo(Bar) overload is used.

一切都清楚了吗?

1 实际上,Microsoft C# 编译器中存在一个错误,它使它成为 any 零常量,而不仅仅是一个整数:

1 There's actually a bug in the Microsoft C# compiler which lets it be any zero constant, not just an integer:

const decimal DecimalZero = 0.0m;

...
Bar x = DecimalZero;

这不太可能得到修复,因为它可能会破坏现有的工作代码.我相信 Eric Lippert 有两个 博客 帖子更详细.

It's unlikely that this will ever be fixed, as it could break existing working code. I believe Eric Lippert has a two blog posts which go into much more detail.

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

The C# specification section 6.1.3 (C# 4 spec) has this to say about it:

隐式枚举转换允许 decimal-integer-literal 0转换为任何枚举类型和任何 nullable-type 其底层type 是一个枚举类型.在后者如果转换由转换为底层的枚举类型并包装结果(§4.1.10).

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 (§4.1.10).

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

That actually suggests that the bug isn't just in allowing the wrong type, but allowing any constant 0 value to be converted rather than only the literal value 0.

它看起来像常数";部分是 在 C# 3 编译器中部分引入.以前是一些个常量值,现在看起来就是全部了.

It looks like the "constant" part was partially introduced in the C# 3 compiler. Previously it was some constant values, now it looks like it's all of them.

这篇关于带有方法重载和枚举的奇怪(可能是错误的?)C# 编译器行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:带有方法重载和枚举的奇怪(可能是错误的?)C# 编译器行为