Variance in Delegates (Visual Basic) (Varianz in Delegaten (Visual Basic))

Mit .NET Framework 3.5 wurde Unterstützung von Varianz eingeführt, um Methodensignaturen und Delegattypen in allen Delegaten in C# und Visual Basic vergleichen zu können. Das bedeutet, dass Sie Delegaten nicht nur Methoden mit übereinstimmenden Signaturen zuweisen können, sondern auch Methoden, die mehrere abgeleitete Typen zurückgeben (Kovarianz) oder die Parameter akzeptieren, die über weniger abgeleitete Typen verfügen, als durch den Delegattyp angegeben wurde (Kontravarianz). Dies umfasst generische und nicht generische Delegaten.

Betrachten Sie beispielsweise folgenden Code, der zwei Klassen und zwei Delegaten aufweist: generisch und nicht generisch.

Public Class First
End Class

Public Class Second
    Inherits First
End Class

Public Delegate Function SampleDelegate(ByVal a As Second) As First
Public Delegate Function SampleGenericDelegate(Of A, R)(ByVal a As A) As R

Beim Erstellen von Delegaten vom Typ SampleDelegate oder SampleDelegate(Of A, R) können Sie diesen Delegaten eine der folgenden Methoden zuweisen.

' Matching signature.
Public Shared Function ASecondRFirst(
    ByVal second As Second) As First
    Return New First()
End Function

' The return type is more derived.
Public Shared Function ASecondRSecond(
    ByVal second As Second) As Second
    Return New Second()
End Function

' The argument type is less derived.
Public Shared Function AFirstRFirst(
    ByVal first As First) As First
    Return New First()
End Function

' The return type is more derived
' and the argument type is less derived.
Public Shared Function AFirstRSecond(
    ByVal first As First) As Second
    Return New Second()
End Function

Das folgende Codebeispiel veranschaulicht die implizite Konvertierung zwischen der Methodensignatur und dem Delegattyp.

' Assigning a method with a matching signature
' to a non-generic delegate. No conversion is necessary.
Dim dNonGeneric As SampleDelegate = AddressOf ASecondRFirst
' Assigning a method with a more derived return type
' and less derived argument type to a non-generic delegate.
' The implicit conversion is used.
Dim dNonGenericConversion As SampleDelegate = AddressOf AFirstRSecond

' Assigning a method with a matching signature to a generic delegate.
' No conversion is necessary.
Dim dGeneric As SampleGenericDelegate(Of Second, First) = AddressOf ASecondRFirst
' Assigning a method with a more derived return type
' and less derived argument type to a generic delegate.
' The implicit conversion is used.
Dim dGenericConversion As SampleGenericDelegate(Of Second, First) = AddressOf AFirstRSecond

Weitere Beispiele finden Sie unter Verwenden von Varianz bei Delegaten (Visual Basic) und Verwenden von Varianz für die generischen Delegaten Func und Action (Visual Basic).

Varianz in generischen Typparametern

In .NET Framework 4 oder höher können Sie implizite Konvertierung zwischen Delegaten aktivieren. Dies bedeutet, dass generische Delegaten, die über verschiedene von generischen Typparametern angegebene Typen verfügen, sich gegenseitig zugewiesen werden können, wenn die Typen voneinander geerbt werden. Dies ist für Varianz erforderlich.

Sie müssen einen generischen Parameter in einem Delegaten mithilfe der Schlüsselwörter in oder out explizit als kovariant oder kontravariant deklarieren, um die implizite Konvertierung zu aktivieren.

Im folgenden Codebeispiel wird veranschaulicht, wie Sie einen Delegaten erstellen können, der über einen kovarianten generischen Typparameter verfügt.

' Type T is declared covariant by using the out keyword.
Public Delegate Function SampleGenericDelegate(Of Out T)() As T
Sub Test()
    Dim dString As SampleGenericDelegate(Of String) = Function() " "
    ' You can assign delegates to each other,
    ' because the type T is declared covariant.
    Dim dObject As SampleGenericDelegate(Of Object) = dString
End Sub

Wenn Sie die Unterstützung von Varianz nur verwenden, um Methodensignaturen mit Delegaten zu vergleichen und nicht die Schlüsselwörter in und out verwenden, kann es möglicherweise passieren, dass Sie zwar Delegate mit identischen Lambdaausdrücken oder -Methoden instanziieren, aber keinen Delegaten einem anderen zuweisen können.

Im folgenden Codebeispiel kann SampleGenericDelegate(Of String) nicht expliziert in SampleGenericDelegate(Of Object) konvertiert werden, obwohl StringObject erbt. Sie können dieses Problem beheben, indem Sie den generischen Parameter T mit dem Schlüsselwort out markieren.

Public Delegate Function SampleGenericDelegate(Of T)() As T
Sub Test()
    Dim dString As SampleGenericDelegate(Of String) = Function() " "

    ' You can assign the dObject delegate
    ' to the same lambda expression as dString delegate
    ' because of the variance support for
    ' matching method signatures with delegate types.
    Dim dObject As SampleGenericDelegate(Of Object) = Function() " "

    ' The following statement generates a compiler error
    ' because the generic type T is not marked as covariant.
    ' Dim dObject As SampleGenericDelegate(Of Object) = dString

End Sub

Generische Delegaten mit varianten Typparametern in .NET Framework

Mit .NET Framework 4 wurde die Unterstützung von Varianz für generische Typparameter in verschiedenen vorhandenen generischen Delegaten eingeführt:

Weitere Informationen sowie Beispiele finden Sie unter Verwenden von Varianz für die generischen Delegaten Func und Action (Visual Basic).

Angeben varianter Typparameter in generischen Delegaten

Wenn ein generischer Delegat über kovariante oder kontravariante generische Typparameter verfügt, kann er als varianter generischer Delegat bezeichnet werden.

Sie können einen generischen Typparameter mithilfe des Schlüsselworts out in einem generischen Delegaten als kovariant deklarieren. Der kovariante Typ kann nur als Typ von Methodenrückgaben und nicht von Methodenargumenten verwendet werden. Das folgende Codebeispiel zeigt, wie Sie einen kovarianten generischen Delegaten deklarieren.

Public Delegate Function DCovariant(Of Out R)() As R

Sie können einen generischen Typparameter mithilfe des Schlüsselworts in in einem generischen Delegaten als kontravariant deklarieren. Der kontravariante Typ kann nur als Typ von Methodenrückgaben und nicht von Methodenargumenten verwendet werden. Das folgende Codebeispiel zeigt, wie Sie einen kontravarianten generischen Delegaten deklarieren.

Public Delegate Sub DContravariant(Of In A)(ByVal a As A)

Wichtig

ByRef-Parameter in Visual Basic können nicht als variant markiert werden.

Es ist auch möglich, Varianz und Kovarianz im gleichen Delegaten, aber für verschiedene Typparameter, zu unterstützen. Dies wird im folgenden Beispiel gezeigt.

Public Delegate Function DVariant(Of In A, Out R)(ByVal a As A) As R

Instanziieren und Aufrufen von varianten generischen Delegaten

Sie können variante Delegaten genau wie invariante Delegaten instanziieren und aufrufen. Im folgenden Beispiel wird der Delegat durch einen Lambdaausdruck instanziiert.

Dim dvariant As DVariant(Of String, String) = Function(str) str + " "
dvariant("test")

Kombinieren von varianten generischen Delegaten

Variante Delegaten sollten nicht kombiniert werden. Die Methode Combine unterstützt keine Konvertierung von varianten Delegaten und erwartet, dass Delegaten vom exakt gleichen Typ sind. Dies kann zu einer Laufzeitausnahme führen, wenn Sie Delegaten entweder mit der Combine-Methode (in C# und Visual Basic) oder dem +-Operator (in C#) kombinieren, wie im folgenden Codebeispiel gezeigt wird.

Dim actObj As Action(Of Object) = Sub(x) Console.WriteLine("object: {0}", x)
Dim actStr As Action(Of String) = Sub(x) Console.WriteLine("string: {0}", x)

' The following statement throws an exception at run time.
' Dim actCombine = [Delegate].Combine(actStr, actObj)

Varianz in generischen Typparametern für Wert- und Referenztypen

Varianz für generische Typparameter wird nur für Referenztypen unterstützt. DVariant(Of Int) kann z. B. nicht implizit in DVariant(Of Object) oder DVariant(Of Long) konvertiert werden, weil es sich bei „Integer“ um einen Werttyp handelt.

Das folgende Beispiel veranschaulicht, dass Varianz in generischen Typparametern für Werttypen nicht unterstützt wird.

' The type T is covariant.
Public Delegate Function DVariant(Of Out T)() As T
' The type T is invariant.
Public Delegate Function DInvariant(Of T)() As T
Sub Test()
    Dim i As Integer = 0
    Dim dInt As DInvariant(Of Integer) = Function() i
    Dim dVariantInt As DVariant(Of Integer) = Function() i

    ' All of the following statements generate a compiler error
    ' because type variance in generic parameters is not supported
    ' for value types, even if generic type parameters are declared variant.
    ' Dim dObject As DInvariant(Of Object) = dInt
    ' Dim dLong As DInvariant(Of Long) = dInt
    ' Dim dVariantObject As DInvariant(Of Object) = dInt
    ' Dim dVariantLong As DInvariant(Of Long) = dInt
End Sub

Gelockerte Delegatenkonvertierung in Visual Basic

Gelockerte Delegatkonvertierung ermöglicht mehr Flexibilität beim Abgleichen von Methodensignaturen mit Delegattypen. Beispielsweise können Sie Parameterspezifikationen und Funktionsrückgabewerte auslassen, wenn Sie einem Delegaten eine Methode zuweisen. Weitere Informationen finden Sie unter Gelockerte Delegatkonvertierung.

Weitere Informationen