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

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

问题描述

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



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



感谢任何帮助,
Grzegorz Kyc

 类程序
{
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);
}
}


解决方案

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

  Bar x = 0; //隐式转换

现在,从0到 Bar 比从0到对象的转换更具体,这就是为什么 Foo(Bar)



是否清除所有内容?






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

  const decimal DecimalZero = 0.0m; 

...
Bar x = DecimalZero;

这不可能修复,因为它可能会破坏现有的工作代码。我相信Eric Lippert有两个博客

C#规范部分6.1.3(C#4规范)具有这就是说:


隐式枚举转换
允许十进制整数字符 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天全站免登陆