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

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

问题描述

今天我发现了一个非常奇怪的行为与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规范) )有这个说法:


隐式枚举转换
允许 decimal-integer-literal 0
转换为任何枚举类型,
转换为任何基于
类型的可枚举类型 >。在后面的
情况下,转换由
转换为底层的枚举类型

并包装结果(§4.1.10)。


这实际上表明,错误不仅仅是允许错误的类型,而是允许任何常量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

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");
    }
}

解决方案

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

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.

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:

const decimal DecimalZero = 0.0m;

...
Bar x = DecimalZero;

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆