Rozptyl delegátů (Visual Basic)

Rozhraní .NET Framework 3.5 zavedlo podporu rozptylu pro porovnávání podpisů metod s typy delegátů ve všech delegátech v jazyce C# a Visual Basic. To znamená, že delegátům můžete přiřadit nejen metody, které mají odpovídající podpisy, ale také metody, které vracejí více odvozených typů (kovariance) nebo přijímají parametry, které mají méně odvozených typů (kontravariance), než které určuje typ delegáta. To zahrnuje obecné i ne generické delegáty.

Představte si například následující kód, který má dvě třídy a dva delegáty: obecné a ne generické.

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

Při vytváření delegátů nebo SampleDelegateSampleDelegate(Of A, R) typů můžete těmto delegátům přiřadit některou z následujících metod.

' 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

Následující příklad kódu znázorňuje implicitní převod mezi podpisem metody a typem delegáta.

' 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

Další příklady najdete v tématu Použití odchylek v delegátech (Visual Basic) a Použití rozptylu pro obecné delegáty func a action (Visual Basic).

Variance v parametrech obecného typu

V rozhraní .NET Framework 4 a novějších můžete povolit implicitní převod mezi delegáty, aby se obecné delegáty, které mají různé typy určené parametry obecného typu, mohli přiřadit navzájem, pokud jsou typy zděděny od sebe podle potřeby rozptylem.

Chcete-li povolit implicitní převod, musíte explicitně deklarovat obecné parametry v delegátu jako kovariantní nebo kontravariant pomocí klíčového slova nebo out klíčového in slova.

Následující příklad kódu ukazuje, jak můžete vytvořit delegáta, který má kovariantní obecný typ parametr.

' 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

Pokud používáte pouze podporu odchylek pro porovnávání podpisů metod s typy delegátů a nepoužíváte in tato out klíčová slova, můžete zjistit, že někdy můžete vytvořit instanci delegátů s identickými výrazy lambda nebo metodami, ale nemůžete přiřadit jednoho delegáta k druhému.

V následujícím příkladu SampleGenericDelegate(Of String) kódu nelze explicitně převést na SampleGenericDelegate(Of Object), ačkoli String dědí Object. Tento problém můžete vyřešit tím, že označíte obecný parametr T klíčovým slovem out .

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

Obecné delegáty, kteří mají parametry variantního typu v rozhraní .NET Framework

Rozhraní .NET Framework 4 zavedlo podporu odchylek pro parametry obecného typu v několika existujících obecných delegátech:

Další informace a příklady naleznete v tématu Použití rozptylu pro obecné delegáty Func a Action (Visual Basic).

Deklarování parametrů variantního typu v obecných delegátech

Pokud má obecný delegát kovariantní nebo kontravariantní parametry obecného typu, může být označován jako variantní obecný delegát.

Pomocí klíčového slova můžete deklarovat kovariantní parametr obecného typu v obecném delegátu out . Kovariantní typ lze použít pouze jako návratový typ metody, nikoli jako typ argumentů metody. Následující příklad kódu ukazuje, jak deklarovat kovariantní obecný delegát.

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

Parametr obecného typu můžete deklarovat kontravariant v obecném delegátu pomocí klíčového in slova. Kontravariantní typ lze použít pouze jako typ argumentů metody, nikoli jako návratový typ metody. Následující příklad kódu ukazuje, jak deklarovat kontravariant obecný delegát.

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

Důležité

ByRef parametry v jazyce Visual Basic nelze označit jako variantu.

Je také možné podporovat odchylku i kovarianci ve stejném delegátu, ale pro různé parametry typu. To je ukázáno v následujícím příkladu.

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

Vytvoření instance a vyvolání obecných delegátů variant

Instance a vyvolání delegátů variant můžete vyvolat stejně jako vytvoření instance a vyvolání invariantní delegáty. V následujícím příkladu vytvoří delegát instanci výrazu lambda.

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

Kombinování obecných delegátů variant

Neměli byste kombinovat variantní delegáty. Metoda Combine nepodporuje převod variantního delegáta a očekává, že delegáti budou přesně stejného typu. To může vést k výjimce za běhu, když zkombinujete delegáty buď pomocí Combine metody (v jazyce C# a Visual Basic), nebo pomocí operátoru + (v jazyce C#), jak je znázorněno v následujícím příkladu kódu.

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)

Rozptyl v parametrech obecného typu pro hodnoty a odkazové typy

Variance parametrů obecného typu je podporována pouze pro odkazové typy. DVariant(Of Int)Například nelze implicitně převést na DVariant(Of Object) nebo DVariant(Of Long), protože celé číslo je typ hodnoty.

Následující příklad ukazuje, že odchylka v parametrech obecného typu není podporována pro typy hodnot.

' 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

Volný převod delegáta v jazyce Visual Basic

Uvolněný převod delegáta umožňuje větší flexibilitu při porovnávání podpisů metod s typy delegátů. Umožňuje například vynechat specifikace parametrů a vynechat návratové hodnoty funkce při přiřazování metody delegátu. Další informace naleznete v tématu Uvolněný převod delegáta.

Viz také