ジェネリックとはアルゴリズムの再利用を可能とする機能で、C++のテンプレートに代わるものです。C++ テンプレートと C# ジェネリックの違い | MSDN
ジェネリックは、おもにコレクションで利用されています。
class MyClass <T> { }ジェネリック クラス - C# プログラミング ガイド | Microsoft Learn
void Method<T>(T val) { }ジェネリック メソッド - C# プログラミング ガイド | Microsoft Learn
共変性 (covariance) と反変性 (contravariance) は、変性 (variance) と総称されます。
たとえば基本クラスBaseと、その派生クラスDerivedがあるとき、
class Base { } class Derived : Base { }
共変性では、派生型を基本型に代入できます。
IEnumerable<Derived> d1 = new List<Derived>(); IEnumerable<Base> b1 = d1; // 派生型を基本型に代入できる // 逆は不可 IEnumerable<Base> b2 = new List<Base>(); IEnumerable<Derived> d2 = b2; // error CS0266
反変性では、基本型を派生型に代入できます。
Action<Base> b1 = (a) => { }; Action<Derived> d1 = b1; // 基本型を派生型に代入できる // 逆は不可 Action<Derived> d2 = (a) => { }; Action<Base> b2 = d2; // error CS0266
型パラメータが共変 (covariant) であることを示し、指定の型よりも 強い 派生の多い (more derived) 型を使用できるようになります。つまり派生型のインスタンスを、基本型の変数に割り当てられます。out キーワード (ジェネリック修飾子) - C# リファレンス | Microsoft Learn
interface Sample<out A> {}
型パラメータが反変 (contravariant) であることを示し、指定の型よりも 弱い 派生の少ない (less derived) 型を使用できるようになります。つまり基本型のインスタンスを、派生型の変数に割り当てられます。in (ジェネリック修飾子) - C# リファレンス | Microsoft Learn
interface Sample<in A> {}
型パラメータに指定できる型を、制約できます。たとえば次のようにクラスが定義されていると、
class A { } class B : A { } class X { } class MyClass1<T> { } // 制約なし class MyClass2<T> where T : A { } // Aを継承するクラスを指定するように要求
これを用いる側は指定されたクラスを継承するか、そのインターフェイスを実装する型を指定する必要があります。
new MyClass1<A>();
new MyClass1<B>();
new MyClass1<X>();
new MyClass2<A>();
new MyClass2<B>();
new MyClass2<X>(); // error CS0311: 型 'X' はジェネリック型またはメソッド 'MyClass2<T>' 内で型パラメーター 'T' として使用できません。'X' から 'A' への暗黙的な参照変換がありません。
制約する型として"class"や"struct"を指定できます。また制約が複数ある場合には、それらを続けて記述します。
class MyClass<T, U> where T : class where U : struct { }
ジェネリック型に、パラメータなしのコンストラクタが必要であることを制約できます。
void Method<T>() where T : IDisposable, new() { T t = new T(); t.Dispose(); }
これによりパラメータなしのコンストラクタがあることが保証されるため、new T()
のように呼び出せるようになります。これを指定しないと「変数型 'T' のインスタンスは、new() 制約を含まないため、作成できません。」としてCS0304になります。他の制約と併用するときには、カンマ区切りで最後に記述します。
型パラメータに指定された型は、typeof()で取得できます。c# - How to get the type of T from a member of a generic class or method - Stack Overflow
void Method<T>(T val) { Type type = typeof(T); }