導入
ジェネリクスはクラスだけでなくメソッド単位でも使えます。「どんな型の配列でも先頭を返す」ような処理を、型ごとに書かずに1つで済ませられます。しかも多くの場合、型は推論されるので <T> を書く必要すらありません。
サンプル
// <T> はメソッド呼び出し時に決まる型パラメータ
T First<T>(T[] items) => items[0];
Console.WriteLine(First(new[] { 3, 1, 2 })); // 3(T は int と推論される)
Console.WriteLine(First(new[] { "x", "y" })); // x(T は string)
// 2つの型パラメータも書ける
TResult Convert<TInput, TResult>(TInput value, Func<TInput, TResult> f) => f(value);
Console.WriteLine(Convert(5, n => n * 2)); // 10
メソッド名<T>(...)で、メソッドごとに型パラメータを持てる- 引数から型が分かるときは
<T>を省略できる(型推論) - LINQ の
Selectなどもジェネリックメソッド
やってみよう
First に空でない double[] を渡したり、Convert の変換ラムダを n => n.ToString() に変えたりして、推論される型が変わる様子を確かめましょう。
演習
T Last<T>(T[] items) => items[items.Length - 1];
// TODO: ジェネリックメソッド Last を使って {10, 20, 30} の末尾を出力してください
Console.WriteLine(___); // 30
- 期待される出力:
30
ヒント1を見る
Last(new[] { 10, 20, 30 }) と書けば T は int と推論されます
ヒント2を見る
型を明示するなら Last<int>(...) ですが、通常は省略できます
まとめ
- ジェネリックメソッドは「メソッド単位で型を抽象化」する
- 引数から型が分かれば
<T>を省略できる(型推論) - 標準ライブラリの多くのメソッドがこの形
次回: 自作の型に「比較」と「等価」のルールを持たせます。