さて、あなたはそれをすべて機能させる最も重要な部分を省略しました。タイプパラメータは、渡された実際のオブジェクトパラメータから推測できます。
例えば:
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
この拡張メソッドは、任意のIEnumerableクラスで機能し、指定したコンバーターに基づいて、列挙内の各項目を別のタイプに変換します。これは標準的なジェネリックです。
現在、このメソッドを呼び出す方法はたくさんあります。
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
4つのバリエーションはすべて同じメソッドを呼び出し、同じ結果を返します。型推論は、渡されたパラメーターを調べ、提供されているものに基づいてそれらの型を自動的に推論することによって機能します。上記の例では、のパラメータにを渡したため、型T
が型であると判断できます。また、 withの初期型と一致するFuncを渡して文字列を返すため、型が型であると推測することもできます。したがって、はのコンバーター関数で埋められます。int
IEnumerable<int>
IEnumerable<T>
U
string
T
int
Func<T, U>
Func<int, string>
上記の推論から、それはその時点での標準的なジェネリックメソッドです。型推論と拡張の方法は、便利さ/構文上の糖衣にすぎません。実際、出力を逆コンパイルすると、拡張メソッドが静的呼び出しに置き換えられ、通常は明示的に入力された型パラメーターで定義されていることがわかります。(これは、逆コンパイラーと設定されたオプションによって異なります)。