ジェネリクス

スポンサーリンク

ジェネリックメソッド

次の Swap メソッドは,任意のデータ型について使うことはできません。
例えば,この Swap メソッドは文字列型について値を交換することはできません。

static void Swap(ref double a, ref double b)
{
    double temp = a;
    a = b;
    b = a;
}

次の Swap<T> メソッドは,任意のデータ型について値の交換ができるようにしたものです。
このように,型パラメータ T を持ったクラスやメソッドを,ジェネリクス (generics) といいます。

static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = a;
}

static void Main()
{
    int m = 1, n = 2;
    Swap<int>(ref m, ref n);
}

型パラメータ T は,メソッド名の直後に Swap<T> のように書きます。
型パラメータが複数必要であれば,Swap<T, U> のように書けばいいです。

ジェネリックメソッドの呼び出しは,Swap<int>(ref m, ref n) のように書きます。
ただし,引数から型の特定が可能な場合は,Swap(ref m, ref n) のように省略していいです。

ジェネリッククラス

次のプログラムは,スタックを実現する Stack<T> クラスを定義したものです。
ジェネリッククラスについては,型の指定 (<int> など) を省略することはできません。

using System;

class Stack<T>
{
    private T[] stack = new T[256];
    private int index = 0;

    public void Push(T item) { stack[index++] = item; }
    public T Pop() { return stack[--index]; }
}

class Program
{
    static void Main()
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(123);
        stack.Pop();
    }
}

型制約

2 引数のうち最大のものを返すジェネリックメソッド Max<T> は次のように書けそうですが,実際にはコンパイルエラーとなります。

// コンパイル不可
// a > b ならば a,そうでなければ b を返す
static T Max<T>(T a, T b)
{
    return a > b ? a : b;
}

コンパイルエラーは,型 T に比較用の演算子 > が定義されていないためです。

次のように where 句によって型 T に制約を与えると,型 T は IComparable インタフェースを実装した型のみが許されます。
ICompareble インタフェースには比較を行う CompareTo メソッドが含まれるので,a.CompareTo(b) と書けば a と b の比較が可能となります。

static T Max<T>(T a, T b)
    where T : IComparable
{
    return a.CompareTo(b) ? a : b;
}
スポンサーリンク