ジェネリック インターフェイスの変性 (Visual Basic)

.NET Framework 4 では、既存のいくつかのジェネリック インターフェイスに対して、変性のサポートが導入されています。 変性のサポートにより、これらのインターフェイスを実装するクラスの暗黙的な変換が可能になりました。 次のインターフェイスは、新たにバリアントになりました。

共変性により、メソッドの戻り値の型の派生を、インターフェイスのジェネリック型パラメーターで定義されている型よりも強くすることができます。 ここでは、共変性機能について説明するために、IEnumerable(Of Object) および IEnumerable(Of String) というジェネリック インターフェイスについて考えます。 IEnumerable(Of String) インターフェイスは、IEnumerable(Of Object) インターフェイスを継承しません。 ただし、String 型は Object 型を継承します。場合によっては、これらのインターフェイスのオブジェクトを、相互に割り当てる必要が生じることもあるでしょう。 これを次のコード例に示します。

Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings

以前のバージョンの .NET Framework では、Option Strict On を使用した Visual Basic でこのコードを実行すると、コンパイル エラーが発生しましたが、 今後は、IEnumerable<T> インターフェイスが共変になったので、上記の例のように、objects の代わりに strings を使用できるようになりました。

反変性により、メソッドの引数の型の派生を、インターフェイスのジェネリック パラメーターで指定されている型よりも弱くすることができます。 ここでは、反変性について説明するために、BaseClass クラスのインスタンスを比較するための BaseComparer クラスを作成した場合について考えます。 BaseComparer クラスは、IEqualityComparer(Of BaseClass) インターフェイスを実装します。 IEqualityComparer<T> インターフェイスが反変になったので、BaseComparer を使用して、BaseClass クラスを継承するクラスのインスタンスを比較することができます。 これを次のコード例に示します。

' Simple hierarchy of classes.
Class BaseClass
End Class

Class DerivedClass
    Inherits BaseClass
End Class

' Comparer class.
Class BaseComparer
    Implements IEqualityComparer(Of BaseClass)

    Public Function Equals1(ByVal x As BaseClass,
                            ByVal y As BaseClass) As Boolean _
                            Implements IEqualityComparer(Of BaseClass).Equals
        Return (x.Equals(y))
    End Function

    Public Function GetHashCode1(ByVal obj As BaseClass) As Integer _
        Implements IEqualityComparer(Of BaseClass).GetHashCode
        Return obj.GetHashCode
    End Function
End Class
Sub Test()
    Dim baseComparer As IEqualityComparer(Of BaseClass) = New BaseComparer
    ' Implicit conversion of IEqualityComparer(Of BaseClass) to
    ' IEqualityComparer(Of DerivedClass).
    Dim childComparer As IEqualityComparer(Of DerivedClass) = baseComparer
End Sub

詳しくは、「ジェネリック コレクションに対するインターフェイスでの変性の使用 (Visual Basic)」を参照してください。

ジェネリック インターフェイスでの変性がサポートされるのは参照型だけです。 値型は変性をサポートしていません。 たとえば、整数は値型によって表されるため、IEnumerable(Of Integer) を暗黙的に IEnumerable(Of Object) に変換することはできません。

Dim integers As IEnumerable(Of Integer) = New List(Of Integer)
' The following statement generates a compiler error
' with Option Strict On, because Integer is a value type.
' Dim objects As IEnumerable(Of Object) = integers

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

' The following statement generates a compiler error
' because classes are invariant.
' Dim list As List(Of Object) = New List(Of String)

' You can use the interface object instead.
Dim listObjects As IEnumerable(Of Object) = New List(Of String)

関連項目