Visual C# 2008 Has A Breaking Change in Generic Method Overload Resolution

へー.こんなバグがあったんですか.まあ C# のオーバーロード解決はこういうバグが生まれやすい土壌がありますからなぁ. (追記) C# 3.0 で型推論のルールを弄った影響かもという気がしてきたので一旦取り下げ.(/追記) C++ ほどじゃないにしても,メソッドオーバーロードに関する仕様はかなりヘビーです.

★その1

1. ジェネリック パラメータと ParamArray パラメータを使用した場合の オーバーロードの解決動作が異なる。
の、C#での動作について。

C#の状況は、Visual Basicの状況と同じでした。C#でも、Visual Studio 2008で仕様が変更されていたんですね。
試したコードは次の通りです。
Visual Studio 2005では "A"、Visual Studio 2008では "B" が表示されます。

public class Class1
{
    public void Method<T>(T a, params int[] b)
    {
        MessageBox.Show("A");
    }
    public void Method<T>(T a, T b)
    {
        MessageBox.Show("B");
    }
}
private void button1_Click(object sender, EventArgs e)
{
    int i = 0;
    short s = 0; // intだとVisual Studio 2005でも同じです。shortって使ったことないかもw
    Class1 c = new Class1();
    c.Method(i, s);
}

C#って Visual Basicよりは互換性に注意を払ってるような気がしていたので、この結果には驚きでした。
#変な偏見とかじゃなくて、言語の方向性がそうなのかなって思ってました。
Visual Studio 2008では、「対象のフレームワーク」でバージョンを指定できるけど、この動作には影響しませんでした。

ちなみに「その2」の方もですが、推論にまかせずに、

c.Method<int>(i, s);

と書けば、Visual Studio 2005でも同じ結果が得られます。

ところで「C#でも、Visual Studio 2008で仕様が変更されていた」と書かれていますが,言語仕様に違反した状態だったのが修正されたといういつものパターンじゃないでしょうかね. (追記) 一旦取り下げ.(/追記)

breaking change について

(Visual) C# が互換性に注意しているというのは実際そうだと思いますが,過去に breaking change が存在しなかったかというとそうでもありません.このあたりは以前『C# うわさ話 - NyaRuRuの日記』でも書きましたが.
そのとき紹介した記事『FYI, C# 2.0 Has A Breaking Change in Enum Subtraction - Fabulous Adventures In Coding』に,似たような話が紹介されています.言語仕様に違反し続けるのと,既に存在するコードを壊してしまうことの間で選択しなきゃいけなくて,断腸の思いで breaking change を行うことがある,と.

Visual C# における言語バージョンの選択

# re: それって、C#ではどうなんですか?(その1〜その3) 2008/05/20 15:54 めたぼ なら

VS2005 Expressインストールしました。

> VS2008では.NET Frameworkのバージョンが違ってもコンパイラは同じなはずです。

でした。
ILレベルで違う。

VS2005では第二引数が配列に挿げ替えられてました。
VS2008では単一の値のまんま。

つまり、VS2008で.NET Frameworkのバージョンが切り変えれるってのは、任意のバージョンのフレームワーク上で動くことを保証するだけであって、VS2005のソース互換を保証することぢゃないんやねぇ。

しかし、ソースレベルで挙動が違うのはいただけないなぁ。
(ーー;)

言語バージョンに絡んでソース互換が欲しいときにまずチェックするべきなのは以下の場所ですね.まあ今回は (多分) バグ修正なので(追記) 一旦取り下げ.(/追記)どっちにしろ breaking change であることに変わりありませんが.

  • プロジェクトのプロパティ
    • Build
      • Advanced


例えば次のコード.『Future Breaking Changes Part One - Fabulous Adventures In Coding』で紹介されているように,C# 1.0 でコンパイルできて,C# 2.0 でコンパイルエラーになります.

class Program  {
    static void M(bool x, bool y) {}
    static void Main() {
        int N = 1, T = 2, U = 3, a = 4, b = 5;
        M(N < T, U > (a+b));
    }
}

これをコンパイルするには Language Version で ISO-1 を選ぶ……って,あれ? Compiler Error CS1644 でエラー起きてるんですが……
Generics 導入後の構文解析器を使い回してんのかー!

追記