ジェネリック クラス (C# プログラミング ガイド)Generic Classes (C# Programming Guide)

ジェネリック クラスは、特定のデータ型に固有ではない操作をカプセル化します。Generic classes encapsulate operations that are not specific to a particular data type. ジェネリック クラスは最も一般的に、リンク リスト、ハッシュ テーブル、スタック、キュー、ツリーなどのコレクションと共に使用されます。The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. コレクションの項目を追加または削除するなどの操作は、保存されているデータの型に関係なく、基本的に同じように実行されます。Operations such as adding and removing items from the collection are performed in basically the same way regardless of the type of data being stored.

コレクション クラスを必要とするほとんどのシナリオで、.NET クラス ライブラリで提供されているものを使用するという方法が推奨されます。For most scenarios that require collection classes, the recommended approach is to use the ones provided in the .NET class library. これらのクラスの使用の詳細については、「.NET のジェネリック コレクション」を参照してください。For more information about using these classes, see Generic Collections in .NET.

通常、ジェネリック クラスを作成するには、既存の具象クラスから始め、汎用性と使いやすさの間で最適なバランスが取れるまで、一度に 1 つずつ型を型パラメーターに変更します。Typically, you create generic classes by starting with an existing concrete class, and changing types into type parameters one at a time until you reach the optimal balance of generalization and usability. 独自のジェネリック クラスを作成するときの重要な考慮事項は次のとおりです。When creating your own generic classes, important considerations include the following:

  • 型パラメーターに汎用化する型。Which types to generalize into type parameters.

    通例、パラメーター化できる型が多ければ多いほど、コードの柔軟性が上がり、再利用しやすくなります。As a rule, the more types you can parameterize, the more flexible and reusable your code becomes. ただし、汎用化が多すぎると、他の開発者にとって読みにくい、理解しにくいコードが生成されます。However, too much generalization can create code that is difficult for other developers to read or understand.

  • 型パラメーターに適用する制約 (制約がある場合) (「型パラメーターの制約」を参照)。What constraints, if any, to apply to the type parameters (See Constraints on Type Parameters).

    処理しなければならない型を処理できる範囲で最大の制約を適用することが推奨されます。A good rule is to apply the maximum constraints possible that will still let you handle the types you must handle. たとえば、ジェネリック クラスが参照型でのみ使用される場合、クラス制約を適用します。For example, if you know that your generic class is intended for use only with reference types, apply the class constraint. それにより、意図しない、値型でのクラスの使用が回避され、Tas 演算子を使用したり、null 値を確認したりできます。That will prevent unintended use of your class with value types, and will enable you to use the as operator on T, and check for null values.

  • 基底クラスやサブクラスの要因としてジェネリック動作を考慮するかどうか。Whether to factor generic behavior into base classes and subclasses.

    ジェネリック クラスは基底クラスとして機能できるので、非ジェネリック クラスと同様の設計考慮事項がここで適用されます。Because generic classes can serve as base classes, the same design considerations apply here as with non-generic classes. ジェネリック基底クラスからの継承ルールについて、このトピックの後半で確認してください。See the rules about inheriting from generic base classes later in this topic.

  • 1 つまたは複数のジェネリック インターフェイスを実装するかどうか。Whether to implement one or more generic interfaces.

    たとえば、ジェネリック基盤のコレクションで項目を作成するために使用されるクラスを設計するとき、場合によっては、IComparable<T> のようなインターフェイスを実装する必要があります。ここで T はクラスの型です。For example, if you are designing a class that will be used to create items in a generics-based collection, you may have to implement an interface such as IComparable<T> where T is the type of your class.

単純なジェネリック クラスの例については、「ジェネリックの概要」を参照してください。For an example of a simple generic class, see Introduction to Generics.

型パラメーターや制約のルールは、特に継承とメンバーのアクセシビリティに関して、ジェネリック クラスの動作と密接な関係があります。The rules for type parameters and constraints have several implications for generic class behavior, especially regarding inheritance and member accessibility. 続行する前に、いくつかの用語を理解してください。Before proceeding, you should understand some terms. ジェネリック クラス Node<T>, の場合、型引数を指定することで、クライアント コードはクラスを参照し、構築されたクローズ型を作成できます (Node<int>)。For a generic class Node<T>, client code can reference the class either by specifying a type argument, to create a closed constructed type (Node<int>). あるいは、ジェネリック基底クラスを指定するときなど、型パラメーターを指定せず、構築されたオープン型を作成できます (Node<T>)。Alternatively, it can leave the type parameter unspecified, for example when you specify a generic base class, to create an open constructed type (Node<T>). ジェネリック クラスは、具象、構築されたクローズ型、または構築されたオープン型の基底クラスから継承できます。Generic classes can inherit from concrete, closed constructed, or open constructed base classes:

class BaseNode { }
class BaseNodeGeneric<T> { }

// concrete type
class NodeConcrete<T> : BaseNode { }

//closed constructed type
class NodeClosed<T> : BaseNodeGeneric<int> { }

//open constructed type 
class NodeOpen<T> : BaseNodeGeneric<T> { }

非ジェネリック クラス、言い換えれば、具象クラスは、構築されたクローズ型の基底クラスから継承できますが、構築されたオープン型のクラスや型パラメーターからは継承できません。ランタイム時、基底クラスのインスタンス化に必要な型引数をクライアント コードが提供できないためです。Non-generic, in other words, concrete, classes can inherit from closed constructed base classes, but not from open constructed classes or from type parameters because there is no way at run time for client code to supply the type argument required to instantiate the base class.

//No error
class Node1 : BaseNodeGeneric<int> { }

//Generates an error
//class Node2 : BaseNodeGeneric<T> {}

//Generates an error
//class Node3 : T {}

構築されたオープン型から継承するジェネリック クラスは、継承クラスで共有されない基底クラスの型パラメーターに対して型引数を提供する必要があります。次のコードをご覧ください。Generic classes that inherit from open constructed types must supply type arguments for any base class type parameters that are not shared by the inheriting class, as demonstrated in the following code:

class BaseNodeMultiple<T, U> { }

//No error
class Node4<T> : BaseNodeMultiple<T, int> { }

//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }

//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {} 

構築されたオープン型から継承するジェネリック クラスは、基底クラスの制約のスーパーセットである (基底クラスの制約を暗黙に定義する) 制約を指定する必要があります。Generic classes that inherit from open constructed types must specify constraints that are a superset of, or imply, the constraints on the base type:

class NodeItem<T> where T : System.IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : System.IComparable<T>, new() { }

ジェネリック型では、次のように、複数の型パラメーターと制約を使用できます。Generic types can use multiple type parameters and constraints, as follows:

class SuperKeyType<K, V, U>
    where U : System.IComparable<U>
    where V : new()
{ }

構築されたオープン型と構築されたクローズ型をメソッド パラメーターとして使用できます。Open constructed and closed constructed types can be used as method parameters:

void Swap<T>(List<T> list1, List<T> list2)
{
    //code to swap items
}

void Swap(List<int> list1, List<int> list2)
{
    //code to swap items
}

ジェネリック クラスでインターフェイスを実装する場合、そのクラスのすべてのインスタンスをそのインターフェイスにキャストできます。If a generic class implements an interface, all instances of that class can be cast to that interface.

ジェネリック クラスは変化しません。Generic classes are invariant. 言い換えると、入力パラメーターが List<BaseClass> を指定するとき、List<DerivedClass> を指定するとコンパイル時エラーが表示されます。In other words, if an input parameter specifies a List<BaseClass>, you will get a compile-time error if you try to provide a List<DerivedClass>.

関連項目See also