質問

オーバーロードの解決に関する奇妙な動作に気づきました。

次のメソッドがあると仮定します:

public static void DoSomething<T>(IEnumerable<T> items)
{
    // Whatever

    // For debugging
    Console.WriteLine("DoSomething<T>(IEnumerable<T> items)");
}

今、私はこのメソッドが少数の明示的な引数でしばしば呼び出されることを知っているので、便宜上、このオーバーロードを追加します:

public static void DoSomething<T>(params T[] items)
{
    // Whatever

    // For debugging
    Console.WriteLine("DoSomething<T>(params T[] items)");
}

これらのメソッドを呼び出そうとしています:

var items = new List<string> { "foo", "bar" };
DoSomething(items);
DoSomething("foo", "bar");

ただし、どちらの場合も、paramsを使用したオーバーロードが呼び出されます。 IEnumerable<T>の場合、List<T>オーバーロードが呼び出されると予想していました。これは(少なくとも私にとっては)より良い一致だと思われるためです。

この動作は正常ですか?誰もそれを説明できますか? MSDNドキュメントでそれに関する明確な情報を見つけることができませんでした...ここに含まれるオーバーロード解決ルールは何ですか?

役に立ちましたか?

解決

ここでは、C#3.0仕様のセクション7.4.3が関連ビットです。基本的にパラメーター配列は展開されているので、比較しています:

public static void DoSomething<T>(T item)

and

public static void DoSomething<T>(IEnumerable<T> item)

最初の一致のTList<string>であると推測され、2番目の一致のstringIEnumerable<string>であると推測されます。

パラメータタイプへの引数に含まれる変換について考えます。最初の変換では、<=>から<=>になります。 2番目では、<=>から<=>です。 7.4.3.4。のルールにより、最初の変換は2番目の変換よりも優れています。

直感に反するビットは型推論です。これを式から外すと、期待どおりに機能します。

var items = new List<string> { "foo", "bar" };
DoSomething<string>(items);
DoSomething<string>("foo", "bar");

その時点では、各呼び出しに適用可能な関数メンバーは1つだけです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top