ジェネリック インターフェイスの分散 (C#)Variance in Generic Interfaces (C#)

.NET Framework 4 では、既存のいくつかのジェネリック インターフェイスに対して、分散のサポートが導入されています。.NET Framework 4 introduced variance support for several existing generic interfaces. 分散のサポートにより、これらのインターフェイスを実装するクラスの暗黙的な変換が可能になりました。Variance support enables implicit conversion of classes that implement these interfaces. 次のインターフェイスは、新たにバリアントになりました。The following interfaces are now variant:

共変性により、メソッドの戻り値の型の派生を、インターフェイスのジェネリック型パラメーターで定義されている型よりも強くすることができます。Covariance permits a method to have a more derived return type than that defined by the generic type parameter of the interface. ここでは、共変性機能について説明するために、IEnumerable<Object> および IEnumerable<String> というジェネリック インターフェイスについて考えます。To illustrate the covariance feature, consider these generic interfaces: IEnumerable<Object> and IEnumerable<String>. IEnumerable<String> インターフェイスは、IEnumerable<Object> インターフェイスを継承しません。The IEnumerable<String> interface does not inherit the IEnumerable<Object> interface. ただし、String 型は Object 型を継承します。場合によっては、これらのインターフェイスのオブジェクトを、相互に割り当てる必要が生じることもあるでしょう。However, the String type does inherit the Object type, and in some cases you may want to assign objects of these interfaces to each other. これを次のコード例に示します。This is shown in the following code example.

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

以前のバージョンの .NET Framework では、Option Strict On を使用した C# でこのコードを実行すると、コンパイル エラーが発生しましたが、In earlier versions of the .NET Framework, this code causes a compilation error in C# with Option Strict On. 今後は、IEnumerable<T> インターフェイスが共変になったので、上記の例のように、objects の代わりに strings を使用できるようになりました。But now you can use strings instead of objects, as shown in the previous example, because the IEnumerable<T> interface is covariant.

反変性により、メソッドの引数の型の派生を、インターフェイスのジェネリック パラメーターで指定されている型よりも弱くすることができます。Contravariance permits a method to have argument types that are less derived than that specified by the generic parameter of the interface. ここでは、反変性について説明するために、BaseClass クラスのインスタンスを比較するための BaseComparer クラスを作成した場合について考えます。To illustrate contravariance, assume that you have created a BaseComparer class to compare instances of the BaseClass class. BaseComparer クラスは、IEqualityComparer<BaseClass> インターフェイスを実装します。The BaseComparer class implements the IEqualityComparer<BaseClass> interface. IEqualityComparer<T> インターフェイスが反変になったので、BaseComparer を使用して、BaseClass クラスを継承するクラスのインスタンスを比較することができます。Because the IEqualityComparer<T> interface is now contravariant, you can use BaseComparer to compare instances of classes that inherit the BaseClass class. これを次のコード例に示します。This is shown in the following code example.

// Simple hierarchy of classes.  
class BaseClass { }  
class DerivedClass : BaseClass { }  

// Comparer class.  
class BaseComparer : IEqualityComparer<BaseClass>   
{  
    public int GetHashCode(BaseClass baseInstance)  
    {  
        return baseInstance.GetHashCode();  
    }  
    public bool Equals(BaseClass x, BaseClass y)  
    {  
        return x == y;  
    }  
}  
class Program  
{  
    static void Test()  
    {  
        IEqualityComparer<BaseClass> baseComparer = new BaseComparer();  

        // Implicit conversion of IEqualityComparer<BaseClass> to   
        // IEqualityComparer<DerivedClass>.  
        IEqualityComparer<DerivedClass> childComparer = baseComparer;  
    }  
}  

詳しくは、「ジェネリック コレクションに対するインターフェイスでの分散の使用 (C#)」をご覧ください。For more examples, see Using Variance in Interfaces for Generic Collections (C#).

ジェネリック インターフェイスでの分散がサポートされるのは参照型だけです。Variance in generic interfaces is supported for reference types only. 値型は変性をサポートしていません。Value types do not support variance. たとえば、整数は値型によって表されるため、IEnumerable<int> を暗黙的に IEnumerable<object> に変換することはできません。For example, IEnumerable<int> cannot be implicitly converted to IEnumerable<object>, because integers are represented by a value type.

IEnumerable<int> integers = new List<int>();  
// The following statement generates a compiler errror,  
// because int is a value type.  
// IEnumerable<Object> objects = integers;  

また、バリアント インターフェイスを実装するクラスは、現在でもインバリアントであることを忘れないようにしてください。It is also important to remember that classes that implement variant interfaces are still invariant. たとえば、List<T> が共変インターフェイス IEnumerable<T> を実装しても、List<Object>List<String> に暗黙的に変換することはできません。For example, although List<T> implements the covariant interface IEnumerable<T>, you cannot implicitly convert List<Object> to List<String>. これを次のコード例に示します。This is illustrated in the following code example.

// The following line generates a compiler error  
// because classes are invariant.  
// List<Object> list = new List<String>();  

// You can use the interface object instead.  
IEnumerable<Object> listObjects = new List<String>();  

関連項目See Also

ジェネリック コレクションに対するインターフェイスでの分散の使用 (C#)Using Variance in Interfaces for Generic Collections (C#)
バリアント ジェネリック インターフェイスの作成 (C#)Creating Variant Generic Interfaces (C#)
ジェネリック インターフェイスGeneric Interfaces
デリゲートの分散 (C#)Variance in Delegates (C#)