问题描述
今天我发现了一个非常奇怪的 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# 编译器行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!