奇怪的C#编译器行为(重载决议)

Vic*_*din 11 .net c# overload-resolution

我发现以下代码的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!?
Run Code Online (Sandbox Code Playgroud)

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

  Expected: 0
  But was:  null
Run Code Online (Sandbox Code Playgroud)

我理解为什么测试失败:p2 = new SqlParameter("@p", 0);被解决为SqlParameter(string, SqlDbType)和其他情况一样SqlParameter(string, object).但我不明白为什么会这样.对我来说它看起来像一个bug,但我不相信C#编译器会有这样的bug.

有什么理由吗?

PS对于任何带有enum参数和0值的方法重载(SqlDbType是枚举)似乎是一个问题.

Tho*_*que 11

基本上,十进制整数文字0可以隐式转换为所有枚举类型(C#4规范§6.1.3),因此编译器确定它SqlParameter(string, SqlDbType)是一个适用的函数成员.然后它必须在两个候选函数成员之间选择更好,并且它选择SqlParameter(string, SqlDbType)SqlParameter(string, object),因为它SqlDbType是比object(§7.5.3.2)更具体的类型.

但我同意在那种情况下它很混乱......

  • @VictorHaydin,因为规范说明了......"隐式枚举转换允许将decimal-integer-literal 0转换为任何枚举类型和任何可以为其类型为枚举类型的可空类型".现在,我不知道为什么它是这样设计的,但可能有一个很好的理由......你需要向C#团队的某个人询问. (5认同)