Victor Haydin
Victor Haydin

Reputation: 3548

Strange C# compiler behavior (overload resolution)

I've found very strange C# compiler behavior for following code:

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

In last line assert fails with following message:

  Expected: 0
  But was:  null

I understand why test fails: p2 = new SqlParameter("@p", 0); is resolved as SqlParameter(string, SqlDbType) and for other cases as SqlParameter(string, object). But I don't understand why this happens. For me it looks like a bug, but I can't believe that C# compiler could have such kind of bug.

Any reasons for this?

P.S. It seems to be a problem for any method overload with enum parameter and 0 value (SqlDbType is enum).

Upvotes: 11

Views: 284

Answers (1)

Thomas Levesque
Thomas Levesque

Reputation: 292455

Basically, the decimal integer literal 0 is implicitly convertible to all enum types (C# 4 spec §6.1.3), so the compiler determines that SqlParameter(string, SqlDbType) is an applicable function member. Then it has to choose the better between two candidates function members, and it picks SqlParameter(string, SqlDbType) over SqlParameter(string, object), because SqlDbType is a more specific type than object (§7.5.3.2).

But I agree that in that case it's very confusing...

Upvotes: 11

Related Questions