奇怪的(可能是错误?)C#编译器行为与方法重载和枚举 [英] Strange (possibly wrong?) C# compiler behavior with method overloading and enums
问题描述
今天我发现了一个非常奇怪的行为与C#函数重载。问题发生在我有一个方法有两个重载,一个接受对象和另一个接受任何类型的枚举。当我传递0作为参数,方法的Enum版本被调用。当我使用任何其他整数值,对象版本被调用。我知道这可以很容易地通过使用显式转换固定,但我想知道为什么编译器的行为这种方式。
下面的代码解释了这个问题(用运行时2.0.50727检查)
感谢您的帮助,
Grzegorz Kyc
{
enum Bar
{
Value1,
Value2,
Value3
}
$ b静态无效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);
}
}
可能是因为你没有注意到从 1 为0到任何枚举的隐式转换:
Bar x = 0; //隐式转换
现在,从0转换到 Bar
比从0到 object
的转换更具体,这就是为什么 Foo(Bar)
overload
1 实际上,Microsoft C#编译器中有一个错误,它允许任何零常数,而不只是一个整数:
const decimal DecimalZero = 0.0m;
...
Bar x = DecimalZero;
这不太可能会被修复,因为它可能会破坏现有的工作代码。我相信Eric Lippert有两个 blog C#规范部分6.1.3(C#4规范) )有这个说法: 隐式枚举转换 这实际上表明,错误不仅仅是允许错误的类型,而是允许任何常量0值被转换,而不只是字面值0。 编辑:看起来常量部分是在C#3编译器中部分介绍。以前是一些常量值,现在看起来像是所有的。 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? The code below explains the problem (checked with runtime 2.0.50727) Thanks for any help on this,
Grzegorz Kyc
It may be that you're not aware that there's an implicit conversion from a constant1 of 0 to any enum: Now, the conversion from 0 to Does that clear everything up? 1 There's actually a bug in the Microsoft C# compiler which lets it be any zero constant, not just an integer: 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. The C# specification section 6.1.3 (C# 4 spec) has this to say about it: 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). 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. EDIT: 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#编译器行为与方法重载和枚举的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
允许 decimal-integer-literal 0
转换为任何枚举类型,
转换为任何基于
类型的可枚举类型 >。在后面的
情况下,转换由
转换为底层的枚举类型
并包装结果(§4.1.10)。
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");
}
}
Bar x = 0; // Implicit conversion
Bar
is more specific than the conversion from 0 to object
, which is why the Foo(Bar)
overload is used.
const decimal DecimalZero = 0.0m;
...
Bar x = DecimalZero;