2011-11-22 15 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.これは、enumパラメータと0値(SqlDbTypeはenum)を使用したメソッドオーバーロードの問題であると思われます。

答えて

11

基本的に、10進整数のリテラル0はすべての列挙型(C#4仕様§6.1.3)に暗黙的に変換されるため、コンパイラはSqlParameter(string, SqlDbType)が該当する関数メンバーであると判断します。 SqlDbTypeobject(7.5.3.2)より具体的な型であるため、SqlParameter(string, object)を超えてSqlParameter(string, SqlDbType)を選択します。最大の警告レベルを設定するとき

しかし、私はそのような場合には、それは非常に混乱だことに同意...

+0

ジャストアイデアは、何が起こりますか?たぶんそれはこの場合警告するでしょう。 – dowhilefor

+0

イェップ、私はそれを持っている。私の質問は:それはなぜ0のためだけに働くのですか? –

+5

@VictorHaydinは、仕様がそうだと言っているからです... "暗黙的な列挙変換により、10進整数 - リテラル0は列挙型に変換され、根底にある型は列挙型になります。"さて、なぜこのように設計されたのか分かりませんが、おそらく良い理由があります。あなたはC#チームの誰かに尋ねる必要があります。 –