共変性と反変性 (C#)

C# では、共変性と反変性により、配列型、デリゲート型、およびジェネリック型引数の暗黙の参照変換が可能になります。 共変性は代入互換性を維持し、反変性はこれを反転させます。

次のコードでは、代入互換性、共変性、および反変性の違いについて説明します。

// Assignment compatibility.
string str = "test";  
// An object of a more derived type is assigned to an object of a less derived type.
object obj = str;  
  
// Covariance.
IEnumerable<string> strings = new List<string>();  
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;  
  
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;  
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;  

配列の共変性により、強い派生型の配列から弱い派生型の配列への暗黙の型変換が可能になります。 ただし、次のコード例に示すように、この操作はタイプ セーフではありません。

object[] array = new String[10];  
// The following statement produces a run-time exception.  
// array[0] = 10;  

メソッド グループの共変性と反変性のサポートにより、メソッド シグネチャをデリゲート型と一致させることができます。 これにより、一致するシグネチャを持つメソッドだけでなく、デリゲート型で指定された型よりも強い派生型 (共変性) を返すメソッドや、弱い派生型 (反変性) のパラメーターを受け取るメソッドを、デリゲートに割り当てることができます。 詳細については、「デリゲートの変性 (C#)」および「デリゲートの変性の使用 (C#)」を参照してください。

次のコード例は、メソッド グループでの共変性と反変性のサポートを示しています。

static object GetObject() { return null; }  
static void SetObject(object obj) { }  
  
static string GetString() { return ""; }  
static void SetString(string str) { }  
  
static void Test()  
{  
    // Covariance. A delegate specifies a return type as object,  
    // but you can assign a method that returns a string.  
    Func<object> del = GetString;  
  
    // Contravariance. A delegate specifies a parameter type as string,  
    // but you can assign a method that takes an object.  
    Action<string> del2 = SetObject;  
}  

.NET Framework 4 以降のバージョンでは、C# でジェネリック インターフェイスと汎用デリゲートでの共変性と反変性がサポートされ、ジェネリック型パラメーターの暗黙の型変換が可能になっています。 詳細については、「ジェネリック インターフェイスの変性 (C#)」および「デリゲートの変性 (C#)」を参照してください。

次のコード例は、ジェネリック インターフェイスの暗黙の参照変換を示しています。

IEnumerable<String> strings = new List<String>();  
IEnumerable<Object> objects = strings;  

ジェネリック インターフェイスや汎用デリゲートは、そのジェネリック パラメーターが共変または反変として宣言されている場合、バリアント と呼ばれます。 C# では、独自のバリアント インターフェイスおよびデリゲートを作成できます。 詳細については、「バリアント ジェネリック インターフェイスの作成 (C#)」および「デリゲートの変性 (C#)」を参照してください。

Title 説明
ジェネリック インターフェイスの変性 (C#) ジェネリック インターフェイスの共変性と反変性について説明し、.NET のバリアント ジェネリック インターフェイスの一覧を示します。
バリアント ジェネリック インターフェイスの作成 (C#) カスタムのバリアント インターフェイスを作成する方法を示します。
ジェネリック コレクションに対するインターフェイスでの変性の使用 (C#) IEnumerable<T> および IComparable<T> インターフェイスでの共変性と反変性のサポートがコードの再利用にどのように役立つかを示します。
デリゲートの変性 (C#) 汎用および非汎用デリゲートの共変性と反変性について説明し、.NET のバリアント汎用デリゲートの一覧を示します。
デリゲートの変性の使用 (C#) 非汎用デリゲートでの共変性と反変性のサポートを使用して、メソッド シグネチャをデリゲート型に一致させる方法について説明します。
Func および Action 汎用デリゲートでの変性の使用 (C#) Func および Action デリゲートでの共変性と反変性のサポートがコードの再利用にどのように役立つかを示します。