次の方法で共有


ジェネリック インターフェイスの変異 (C#)

.NET Framework 4 では、複数の既存のジェネリック インターフェイスに差異のサポートが導入されました。 分散のサポートにより、これらのインターフェイスを実装するクラスの暗黙的な変換が可能になります。

.NET Framework 4 以降では、次のインターフェイスがバリアントです。

.NET Framework 4.5 以降では、次のインターフェイスがバリアントです。

共分散により、メソッドは、インターフェイスのジェネリック型パラメーターで定義された戻り値よりも派生した戻り値の型を持つことができます。 共分散機能を説明するには、 IEnumerable<Object>IEnumerable<String>の一般的なインターフェイスを検討してください。 IEnumerable<String> インターフェイスは、IEnumerable<Object> インターフェイスを継承しません。 ただし、 String 型は Object 型を継承します。場合によっては、これらのインターフェイスのオブジェクトを相互に割り当てることができます。 これは次のコードに示されています。

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

以前のバージョンの .NET Framework では、このコードは C# でコンパイル エラーを引き起こし、 Option Strict が有効な場合は Visual Basic でエラーが発生します。 ただし、前の例に示すように、stringsではなくobjectsを使用できるようになりました。これは、IEnumerable<T> インターフェイスが共変であるためです。

反変性により、メソッドは、インターフェイスのジェネリック パラメーターで指定されたよりも派生度の低い引数型を持つことができます。 反変性を示すために、BaseComparer クラスのインスタンスを比較するBaseClass クラスが作成されていることを前提としています。 BaseComparer クラスは IEqualityComparer<BaseClass> インターフェイスを実装しています。 IEqualityComparer<T> インターフェイスは反変であるため、BaseComparerを使用して、BaseClass クラスを継承するクラスのインスタンスを比較できます。 これは次のコードに示されています。

// 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#)」を参照してください。

ジェネリック インターフェイスの差異は、参照型でのみサポートされます。 値型は分散をサポートしていません。 たとえば、整数は値型で表されるため、 IEnumerable<int> を暗黙的に IEnumerable<object>に変換することはできません。

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

また、バリアント インターフェイスを実装するクラスは不変であることにも注意してください。 たとえば、 List<T> は共変インターフェイス IEnumerable<T>を実装しますが、 List<String>List<Object>に暗黙的に変換することはできません。 これを次のコード例に示します。

// 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>();

こちらも参照ください