ジェネリックを使用すると、操作対象のデータ型に厳密に合わせてメソッド、クラス、構造体、またはインターフェイスを調整できます。 たとえば、キーと値を任意の型にできる Hashtable クラスを使用する代わりに、 Dictionary<TKey,TValue> ジェネリック クラスを使用し、キーと値に許可される型を指定できます。 ジェネリックの利点の中には、コードの再利用性とタイプ セーフの向上があります。
ジェネリックを定義して使用する
ジェネリックは、格納または使用する 1 つ以上の型のプレースホルダー (型パラメーター) を持つクラス、構造体、インターフェイス、およびメソッドです。 ジェネリック コレクション クラスでは、格納するオブジェクトの型のプレースホルダーとして型パラメーターを使用できます。 型パラメーターは、フィールドの型とそのメソッドのパラメーター型として表示されます。 ジェネリック メソッドでは、戻り値の型として、またはその仮パラメーターのいずれかの型として、その型パラメーターを使用できます。
次のコードは、単純なジェネリック クラス定義を示しています。
public class SimpleGenericClass<T>
{
public T Field;
}
Public Class SimpleGenericClass(Of T)
Public Field As T
End Class
ジェネリック クラスのインスタンスを作成するときは、型パラメーターの代わりに実際の型を指定します。 これにより、構築されたジェネリック クラスと呼ばれる新しいジェネリック クラスが確立され、選択した型が型パラメーターが表示されるすべての場所で置き換えられます。 結果は、次のコードに示すように、型の選択に合わせて調整された型セーフ クラスです。
public static void Main()
{
SimpleGenericClass<string> g = new SimpleGenericClass<string>();
g.Field = "A string";
//...
Console.WriteLine($"SimpleGenericClass.Field = \"{g.Field}\"");
Console.WriteLine($"SimpleGenericClass.Field.GetType() = {g.Field.GetType().FullName}");
}
Public Shared Sub Main()
Dim g As New SimpleGenericClass(Of String)
g.Field = "A string"
'...
Console.WriteLine("SimpleGenericClass.Field = ""{0}""", g.Field)
Console.WriteLine("SimpleGenericClass.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub
用語
次の用語は、.NET のジェネリックについて説明するために使用されます。
ジェネリック型定義は、テンプレートとして機能するクラス、構造体、またはインターフェイスの宣言であり、含めるか使用できる型のプレースホルダーを含みます。 たとえば、 System.Collections.Generic.Dictionary<TKey,TValue> クラスには、キーと値の 2 種類を含めることができます。 ジェネリック型定義はテンプレートのみであるため、ジェネリック型定義であるクラス、構造体、またはインターフェイスのインスタンスを作成することはできません。
ジェネリック型パラメーターまたは 型パラメーターは、ジェネリック型またはメソッド定義のプレースホルダーです。 System.Collections.Generic.Dictionary<TKey,TValue>ジェネリック型には、キーと値の型を表す 2 つの型パラメーター (
TKey
とTValue
) があります。構築されたジェネリック型 (構築型) は、ジェネリック型定義のジェネリック型パラメーターの型を指定した結果です。
ジェネリック型引数は、ジェネリック型パラメーターに置き換える任意の型です。
ジェネリック 型 という一般的な用語には、構築された型とジェネリック型の定義の両方が含まれます。
ジェネリック型パラメーターの共変性と反変性を使用すると、型引数がターゲット構築型よりも派生型 (共変性) 以下の派生型 (反変性) を持つ、構築されたジェネリック型を使用できます。 共変性と反変性は、まとめて 分散と呼ばれます。 詳細については、「 共変性と反変性」を参照してください。
制約 は、ジェネリック型パラメーターに適用される制限です。 たとえば、型パラメーターを、 System.Collections.Generic.IComparer<T> ジェネリック インターフェイスを実装する型に制限して、型のインスタンスを順序付けできるようにします。 また、型パラメーターを、特定の基底クラスを持つ型、パラメーターなしのコンストラクターを持つ型、または参照型または値型である型に制限することもできます。 ジェネリック型のユーザーは、制約を満たしていない型引数を置き換えることはできません。
ジェネリック メソッド定義は、ジェネリック型パラメーターのリストと仮パラメーターのリストという 2 つのパラメーター リストを持つメソッドです。 型パラメーターは、次のコードに示すように、戻り値の型または仮パラメーターの型として表示できます。
T MyGenericMethod<T>(T arg) { T temp = arg; //... return temp; }
Function MyGenericMethod(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function
ジェネリック メソッドは、ジェネリック型または非ジェネリック型で使用できます。 重要なのは、メソッド自体がジェネリック型に属しているからといって、または、そのメソッドが囲んでいる型のジェネリックパラメーターである仮パラメーターを持っているからといって、必ずしもジェネリックであるとは限らないということです。 メソッドは、型パラメーターの独自のリストがある場合にのみジェネリックです。 次のコードでは、メソッド
G
のみがジェネリックです。class A { T G<T>(T arg) { T temp = arg; //... return temp; } } class MyGenericClass<T> { T M(T arg) { T temp = arg; //... return temp; } }
Class A Function G(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class Class MyGenericClass(Of T) Function M(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class
ジェネリックの長所と短所
ジェネリック コレクションとデリゲートを使用する利点は多数あります。
型安全性 ジェネリックは、型の安全性の負担をコンパイラに移します。 コンパイル時に適用されるため、正しいデータ型をテストするコードを記述する必要はありません。 型キャストの必要性と実行時エラーの可能性が軽減されます。
コードを減らし、コードをより簡単に再利用できるようにします。 基底クラスを継承してメンバーをオーバーライドする必要はありません。 たとえば、 LinkedList<T> はすぐに使用できる状態です。 たとえば、次の変数宣言を使用して、文字列のリンクリストを作成できます。
LinkedList<string> llist = new LinkedList<string>();
Dim llist As New LinkedList(Of String)()
パフォーマンスの向上。 一般に、ジェネリック コレクション型は、値型をボックス化する必要がないため、値型の格納と操作に適しています。
ジェネリック デリゲートを使用すると、複数のデリゲート クラスを作成しなくても、タイプ セーフなコールバックが可能になります。 たとえば、Predicate<T>ジェネリック デリゲートを使用すると、特定の型の独自の検索条件を実装するメソッドを作成し、Array、Find、FindLastなどのFindAll型のメソッドでメソッドを使用できます。
ジェネリックは、動的に生成されたコードを合理化します。 動的に生成されたコードでジェネリックを使用する場合、型を生成する必要はありません。 これにより、アセンブリ全体を生成する代わりに軽量の動的メソッドを使用できるシナリオの数が増加します。 詳細については、「」を参照してください。
ジェネリックのいくつかの制限事項を次に示します。
ジェネリック型は、 MarshalByRefObject などのほとんどの基底クラスから派生できます (また、制約を使用して、ジェネリック型パラメーターが MarshalByRefObject などの基底クラスから派生することを要求できます)。 ただし、.NET では、コンテキスト バインドジェネリック型はサポートされていません。 ジェネリック型は ContextBoundObjectから派生できますが、その型のインスタンスを作成しようとすると、 TypeLoadExceptionが発生します。
列挙型にジェネリック型パラメーターを指定することはできません。 列挙体は、付随的にのみジェネリックにすることができます (たとえば、Visual Basic、C#、または C++ を使用して定義されたジェネリック型に入れ子になっているためです)。 詳細については、 共通型システムの「列挙型」を参照してください。
軽量の動的メソッドをジェネリックにすることはできません。
Visual Basic、C#、および C++ では、ジェネリック型で囲まれた入れ子になった型は、外側のすべての型の型パラメーターに型が割り当てられていない限り、インスタンス化できません。 もう 1 つの言い方は、リフレクションでは、これらの言語を使用して定義された入れ子になった型に、外側のすべての型の型パラメーターが含まれていることです。 これにより、包含する型の型パラメーターを、入れ子になった型のメンバー定義で使用することができます。 詳細については、 MakeGenericTypeの「ネストされた型」を参照してください。
注
動的アセンブリでコードを出力するか、 Ilasm.exe (IL アセンブラー) を使用して定義される入れ子になった型は、外側の型の型パラメーターを含める必要はありません。ただし、型パラメーターが含まれていない場合、型パラメーターは入れ子になったクラスのスコープ内にありません。
詳細については、 MakeGenericTypeの「ネストされた型」を参照してください。
クラス ライブラリと言語のサポート
.NET には、次の名前空間に多数のジェネリック コレクション クラスが用意されています。
System.Collections.Generic名前空間には、List<T>やDictionary<TKey,TValue>ジェネリック クラスなど、.NET によって提供されるほとんどのジェネリック コレクション型が含まれています。
System.Collections.ObjectModel名前空間には、クラスのユーザーにオブジェクト モデルを公開するのに役立つ、ReadOnlyCollection<T> ジェネリック クラスなどの追加のジェネリック コレクション型が含まれています。
並べ替えと等価比較を実装するためのジェネリック インターフェイスは、イベント ハンドラー、変換、および検索述語のジェネリック デリゲート型と共に、 System 名前空間で提供されます。
System.Numerics名前空間は、数学機能 (.NET 7 以降のバージョンで利用可能) のジェネリック インターフェイスを提供します。 詳細については、「 一般的な数学」を参照してください。
ジェネリック型とジェネリック メソッドを調べるための System.Reflection 名前空間、ジェネリック型とメソッドを含む動的アセンブリを出力するための System.Reflection.Emit 、およびジェネリックを含むソース グラフを生成するための System.CodeDom のサポートが追加されました。
共通言語ランタイムは、 Stelem、 Ldelem、 Unbox_Any、 Constrained、 Readonlyなど、共通中間言語 (CIL) のジェネリック型をサポートする新しいオペコードとプレフィックスを提供します。
Visual C++、C#、Visual Basic はすべて、ジェネリックの定義と使用を完全にサポートします。 言語サポートの詳細については、「 Visual Basic のジェネリック型」、Visual C++ の 「ジェネリックの概要」、および「 ジェネリックの概要」を参照してください。
入れ子になった型とジェネリック
ジェネリック型で入れ子になっている型は、外側のジェネリック型の型パラメーターに依存できます。 共通言語ランタイムは、入れ子になった型が独自のジェネリック型パラメーターを持っていない場合でも、ジェネリックと見なします。 入れ子になった型のインスタンスを作成するときは、外側のすべてのジェネリック型に型引数を指定する必要があります。
関連資料
タイトル | 説明 |
---|---|
.NET のジェネリック コレクション | .NET のジェネリック コレクション クラスとその他のジェネリック型について説明します。 |
配列とリストを操作するための汎用デリゲート | 配列またはコレクションの要素に対して実行される変換、検索述語、およびアクションのジェネリック デリゲートについて説明します。 |
一般的な数学 | 数学演算を一般的に実行する方法について説明します。 |
ジェネリック インターフェイス | ジェネリック型のファミリ間で共通の機能を提供するジェネリック インターフェイスについて説明します。 |
共変性と反変性 | ジェネリック型パラメーターの共変性と反変性について説明します。 |
一般的に使用されるコレクション型 | ジェネリック型など、.NET のコレクション型の特性と使用シナリオに関する概要情報を提供します。 |
ジェネリック コレクションを使用する場合 | ジェネリック コレクション型を使用するタイミングを決定するための一般的な規則について説明します。 |
方法: リフレクション出力を使用してジェネリック型を定義する | ジェネリック型とメソッドを含む動的アセンブリを生成する方法について説明します。 |
Visual Basic のジェネリック型 | ジェネリック型の使用と定義に関するハウツー トピックなど、Visual Basic ユーザー向けのジェネリック機能について説明します。 |
ジェネリックの概要 | C# ユーザーのジェネリック型の定義と使用の概要について説明します。 |
Visual C++ のジェネリックの概要 | ジェネリックとテンプレートの違いなど、C++ ユーザーのジェネリック機能について説明します。 |
リファレンス
.NET