Varianz in generischen Schnittstellen (C# und Visual Basic)

In .NET Framework 4 wird die Varianzunterstützung für mehrere vorhandene generische Schnittstellen eingeführt. Die Varianzunterstützung ermöglicht die implizite Konvertierung von Klassen, die diese Schnittstellen implementieren. Folgenden Schnittstellen sind jetzt variant:

Kovarianz erlaubt einer Methode, einen stärker abgeleiteten Rückgabetyp zu verwenden, als vom generischen Typparameter der Schnittstelle definiert wurde. Folgende generische Schnittstellen veranschaulichen die Kovarianzfunktion: IEnumerable<Object> und IEnumerable<String> (IEnumerable(Of Object) und IEnumerable(Of String) in Visual Basic). Die IEnumerable<String>-Schnittstelle (IEnumerable(Of String) in Visual Basic) erbt die nicht die IEnumerable<Object>-Schnittstelle (IEnumerable(Of Object) in Visual Basic). Der String-Typ erbt jedoch den Object-Typ, und in einigen Fällen können Sie Objekte dieser Schnittstellen einander zuweisen. Dies wird im folgenden Codebeispiel veranschaulicht.

Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

In früheren Versionen von .NET Framework wird durch diesen Code bei Option Strict On ein Kompilierungsfehler in C# und in Visual Basic verursacht. Jetzt können Sie jedoch strings anstelle von objects verwenden, wie im vorherigen Beispiel veranschaulicht, da die IEnumerable<T>-Schnittstelle kovariant ist.

Kontravarianz ermöglicht einer Methode, weniger stark abgeleitete Argumenttypen zu verwenden, als durch den generischen Parameter der Schnittstelle angegeben wird. Zur Veranschaulichung der Kontravarianz wird angenommen, dass Sie eine BaseComparer-Klasse erstellt haben, um Instanzen der BaseClass-Klasse zu vergleichen. Die BaseComparer-Klasse implementiert die IEqualityComparer<BaseClass>-Schnittstelle (IEqualityComparer(Of BaseClass) in Visual Basic). Da die IEqualityComparer<T>-Schnittstelle jetzt kontravariant ist, können Sie mit BaseComparer Instanzen von Klassen vergleichen, die die BaseClass-Klasse erben. Dies wird im folgenden Codebeispiel veranschaulicht.

' 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
// 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;
    }
}

Weitere Beispiele finden Sie unter Verwenden von Varianz in Schnittstellen für generische Auflistungen (C# und Visual Basic).

Varianz wird in generischen Schnittstellen nur für Verweistypen unterstützt. Werttypen unterstützen keine Varianz. Beispielsweise kann IEnumerable<int> (IEnumerable(Of Integer) in Visual Basic) nicht implizit in IEnumerable<object> (IEnumerable(Of Object) in Visual Basic) konvertiert werden, da ganze Zahlen durch einen Werttyp dargestellt werden.

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

Außerdem sollte nicht vergessen werden, dass Klassen, die variante Schnittstellen implementieren, selbst nicht variant sind. Obwohl List<T> beispielsweise die kovariante IEnumerable<T>-Schnittstelle implementiert, können Sie List<Object> nicht implizit in List<String> (List(Of Object) in List(Of String) in Visual Basic) konvertieren. Dies wird im folgenden Codebeispiel gezeigt.

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

Siehe auch

Referenz

Verwenden von Varianz in Schnittstellen für generische Auflistungen (C# und Visual Basic)

Konzepte

Erstellen varianter generischer Schnittstellen (C# und Visual Basic)

Generische Schnittstellen

Varianz in Delegaten (C# und Visual Basic)