2011-11-22 53 views
11

我发现很奇怪的C#编译器的行为如下代码:奇怪的C#编译器行为(重载)

var p1 = new SqlParameter("@p", Convert.ToInt32(1)); 
    var p2 = new SqlParameter("@p", 1); 
    Assert.AreEqual(p1.Value, p2.Value); // PASS 

    var x = 0; 
    p1 = new SqlParameter("@p", Convert.ToInt32(x)); 
    p2 = new SqlParameter("@p", x); 
    Assert.AreEqual(p1.Value, p2.Value); // PASS 

    p1 = new SqlParameter("@p", Convert.ToInt32(0)); 
    p2 = new SqlParameter("@p", 0); 
    Assert.AreEqual(p1.Value, p2.Value); // FAIL!? 

在最后一行断言失败,以下消息:

Expected: 0 
    But was: null 

我明白为什么测试失败:p2 = new SqlParameter("@p", 0);解析为SqlParameter(string, SqlDbType),其他情况下为SqlParameter(string, object)。但我不明白为什么会发生这种情况。对我来说,它看起来像一个错误,但我不相信C#编译器可能有这样的错误。

有什么理由呢?

P.S.使用枚举参数和0值(SqlDbType是枚举)的任何方法重载似乎是一个问题。

回答

11

基本上,十进制整数字面0隐式转换为所有枚举类型(C#4规范§6.1.3),所以编译器确定SqlParameter(string, SqlDbType)是适用的功能部件。然后它必须选择两个候选职能成员之间的更好,并且它选择SqlParameter(string, SqlDbType)而不是SqlParameter(string, object),因为SqlDbType是比object(第7.5.3.2节)更具体的类型。

但我认为,在这种情况下,这是非常令人困惑......

+0

只是一个想法,设置警告级别设置为最大时,会发生什么?也许它会在这种情况下提醒你。 – dowhilefor

+0

Yeap,我明白了。我的问题是:为什么它只适用于0? –

+5

@VictorHaydin,因为规范是这么说的......“隐式枚举转换允许将小数整数字面量0转换为任何枚举类型和任何基类型为枚举类型的可空类型”。现在,我不知道它为什么是这样设计的,但可能有一个很好的理由......您需要从C#团队中找人。 –