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

时间:2011-11-22 14:44:52

标签: c# .net 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!?

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

  Expected: 0
  But was:  null

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

有什么原因吗?

P.S。对于具有enum参数和0值的任何方法重载(SqlDbType是枚举),这似乎是一个问题。

1 个答案:

答案 0 :(得分:11)

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

但我同意,在这种情况下,这非常令人困惑......