Unity & C# 学習教材

ジェネリックメソッド

型パラメータはクラス全体ではなく、メソッド単体に付けることもできます。特定のメソッドだけを汎用化したいときや、型推論を活用して呼び出し側を簡潔に書きたいときに使います。

学習目標

前提知識


1. ジェネリックメソッドの定義

書式:ジェネリックメソッドの定義

1
2
3
戻り値の型 メソッド名<型パラメータ>(引数リスト)
{
}
要素 説明
<型パラメータ> メソッド名の直後に書く。戻り値の型や引数の型として使える
1
2
3
4
static T Identity<T>(T value)
{
    return value;
}
1
2
int n = Identity<int>(42);
string s = Identity<string>("hello");
1
2
42
hello

2. 型推論

引数の型からコンパイラが T を推論できる場合、<T> を省略できます。

1
2
int n = Identity(42);       // T = int と推論される
string s = Identity("hi");  // T = string と推論される

型推論が効くのは 型パラメータが引数の型に現れる場合です。戻り値だけに T が出てくる場合は推論できないため、明示的に指定が必要になります。

1
2
3
4
5
6
7
8
// 戻り値にのみ T が使われる例: 推論不可
T Default<T>()
{
    return default;
}

// 呼び出し側は型を明示する必要がある
int zero = Default<int>();

3. 複数のパラメータと戻り値への応用

型パラメータが引数に複数現れる場合も書き方は同じです。

1
2
3
4
static Pair<T1, T2> MakePair<T1, T2>(T1 first, T2 second)
{
    return new Pair<T1, T2>(first, second);
}
1
Pair<int, string> p = MakePair(1, "alpha");  // T1=int, T2=string と推論される

💡 ポイント: 型推論は左辺の型ではなく、渡した引数の型を見て行われます。


4. ジェネリッククラスのメソッドとの使い分け

ジェネリッククラスのメソッドが使うのはクラスに付いた T です。一方、ジェネリックメソッドはそのメソッド専用の T を持ちます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Container<T>
{
    public T Value { get; set; }

    // クラスの T を使う(Container<int> なら T=int)
    public bool Equals(T other)
    {
        return Value?.Equals(other) ?? false;
    }

    // メソッド専用の型パラメータ U — Container<T> を Container<U> に変換する
    public Container<U> Cast<U>(U newValue)
    {
        return new Container<U> { Value = newValue };
    }
}
1
2
3
4
Container<int> intBox = new Container<int> { Value = 42 };

// Cast<U> はメソッド専用の U を持つ
Container<string> strBox = intBox.Cast("hello");

使い分けの基準:


よくあるミス

1
2
3
4
5
6
// ❌ NG: 型パラメータが引数に現れないのに型推論を期待している
T Zero<T>() => default;
int z = Zero();  // コンパイルエラー: T を推論できない

// ✅ OK: 型を明示する
int z = Zero<int>();

まとめ


理解度チェック

  1. 次のメソッドの呼び出し Wrap(100) で型推論は効きますか? 理由とともに答えてください。

    1
    2
    3
    4
    
    static Container<T> Wrap<T>(T value)
    {
        return new Container<T> { Value = value };
    }
    
  2. 次のメソッドを型推論なしで呼び出す場合の書き方は?

    1
    2
    
    static T Clone<T>(T source) { return source; }
    string s = Clone("hello");
    
  3. (応用)2 つの値の大きい方を返すジェネリックメソッド Max<T>IComparable<T> を使って書いてください(型制約は次のページで正式に学びます)。

解答を見る
  1. 型推論は効きます。引数 value の型 100int)から T = int と推論できます。

  2. string s = Clone<string>("hello");

  3. 1
    2
    3
    4
    
    static T Max<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) >= 0 ? a : b;
    }
    

次のステップ

型制約 では、型パラメータに条件を付けることで、T に対して使える操作を増やす方法を学びます。