ジェネリック クラスとメソッド

ジェネリックにより、.NET に型パラメーターという概念が導入されます。 ジェネリックを使用すると、コードでクラスやメソッドを使用するまで 1 つ以上の型パラメーターの指定を遅延させるクラスおよびメソッドを設計することができます。 たとえば、ジェネリック型パラメーター T を使用すると、次に示すように、ランタイム キャストやボックス化操作を使うコストやリスクを発生させることなく他のクライアント コードで使用できる、単一のクラスを記述できます。

// Declare the generic class.
public class GenericList<T>
{
    public void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        // Declare a list of type int.
        GenericList<int> list1 = new GenericList<int>();
        list1.Add(1);

        // Declare a list of type string.
        GenericList<string> list2 = new GenericList<string>();
        list2.Add("");

        // Declare a list of type ExampleClass.
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
        list3.Add(new ExampleClass());
    }
}

ジェネリックのクラスとメソッドにより、非ジェネリックの場合には不可能な方法で、再利用性、タイプ セーフ、効率性が同時に実現されます。 ジェネリック型パラメーターは、コンパイル時に型引数に置き換えられます。 前の例では、コンパイラによって Tint に置き換えられます。 ジェネリックは、コレクションとそれを操作するメソッドとともに使用されるのが通常です。 System.Collections.Generic 名前空間には、ジェネリック ベースのコレクション クラスがいくつか含まれています。 ArrayList などの非ジェネリック コレクションは推奨されません。これらは互換性のためだけに保持されています。 詳細については、「.NET のジェネリック」を参照してください。

カスタムのジェネリック型やジェネリック メソッドを作成して、タイプ セーフで効率的な独自の汎用ソリューションや設計パターンを実現することもできます。 次のコード例では、デモンストレーション用の簡単なジェネリックのリンク リスト クラスを示します。 (通常は、独自のクラスを作成するのではなく、.NET で用意されている List<T> クラスを使用してください。)この例では、通常、具体的な型を使用して、リストに格納する項目の型を示す場面で、型パラメーター T を使用しています。

  • AddHead メソッドのメソッド パラメーターの型として使用。
  • 入れ子になった Node クラスの Data プロパティの戻り値の型として使用。
  • 入れ子になったクラスのプライベート メンバー data の型として使用。

T は、入れ子になった Node クラスで使用できます。 GenericList<T> が、具体的な型を使用して、たとえば GenericList<int> としてインスタンス化されると、T の部分はそれぞれ int に置き換えられます。

// type parameter T in angle brackets
public class GenericList<T>
{
    // The nested class is also generic on T.
    private class Node
    {
        // T used in non-generic constructor.
        public Node(T t)
        {
            next = null;
            data = t;
        }

        private Node? next;
        public Node? Next
        {
            get { return next; }
            set { next = value; }
        }

        // T as private member data type.
        private T data;

        // T as return type of property.
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
    }

    private Node? head;

    // constructor
    public GenericList()
    {
        head = null;
    }

    // T as method parameter type:
    public void AddHead(T t)
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }

    public IEnumerator<T> GetEnumerator()
    {
        Node? current = head;

        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }
}

次のコード例では、クライアント コードでジェネリックの GenericList<T> クラスを使用して、整数のリストを作成する方法を示しています。 型引数を変更すると、次のコードによって、文字列またはその他のカスタム型のリストが作成されます。

class TestGenericList
{
    static void Main()
    {
        // int is the type argument
        GenericList<int> list = new GenericList<int>();

        for (int x = 0; x < 10; x++)
        {
            list.AddHead(x);
        }

        foreach (int i in list)
        {
            System.Console.Write(i + " ");
        }
        System.Console.WriteLine("\nDone");
    }
}

Note

ジェネリック型はクラスに限定されません。 前の例では class 型が使用されていますが、ジェネリック interface 型と struct 型 (record 型を含む) を定義できます。

ジェネリックの概要

  • ジェネリック型は、コードの再利用、タイプ セーフ、およびパフォーマンスを最大化するために使用します。
  • ジェネリックの最も一般的な用途は、コレクション クラスの作成です。
  • .NET クラス ライブラリには、複数のジェネリック コレクション クラスが System.Collections.Generic 名前空間に含まれています。 System.Collections 名前空間の ArrayList などのクラスの代わりとして、ジェネリック コレクションをできる限り使用してください。
  • 独自のジェネリック インターフェイス、クラス、メソッド、イベント、およびデリゲートを作成できます。
  • ジェネリック クラスは、特定のデータ型のメソッドへのアクセスを有効にするように制限できます。
  • ジェネリック データ型で使用される型に関する情報を実行時に取得するには、リフレクションを使用します。

C# 言語仕様

詳細については、「C# 言語の仕様」を参照してください。

関連項目