オーバーロード、ジェネリック型推論、および「params」キーワード
-
10-07-2019 - |
質問
オーバーロードの解決に関する奇妙な動作に気づきました。
次のメソッドがあると仮定します:
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)
最初の一致のT
はList<string>
であると推測され、2番目の一致のstring
はIEnumerable<string>
であると推測されます。
パラメータタイプへの引数に含まれる変換について考えます。最初の変換では、<=>から<=>になります。 2番目では、<=>から<=>です。 7.4.3.4。のルールにより、最初の変換は2番目の変換よりも優れています。
直感に反するビットは型推論です。これを式から外すと、期待どおりに機能します。
var items = new List<string> { "foo", "bar" };
DoSomething<string>(items);
DoSomething<string>("foo", "bar");
その時点では、各呼び出しに適用可能な関数メンバーは1つだけです。
所属していません StackOverflow