共用方式為


委派中的變數 (Visual Basic)

.NET Framework 3.5 引入了變異支援,以便在 C# 和 Visual Basic 中,比對所有委派的簽章與委派類型。 這表示您可以不僅指派給具有相符簽章的方法,還可以指派給回傳更具衍生型別(協變)的方法,或者接受比委派類型所指定的衍生型別較少的參數(逆變)的方法。 這包括泛型和非泛型委派。

例如,請考慮下列程序代碼,其具有兩個類別和兩個委派:泛型和非泛型。

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

當您建立 SampleDelegateSampleDelegate(Of A, R) 類型的委派時,您可以將下列任一種方法指派給這些委派。

' 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

下列程式代碼範例說明方法簽章與委派類型之間的隱含轉換。

' 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

如需更多範例,請參閱在委派中使用變數 (Visual Basic) 和使用 Func 和 Action 泛型委派的變異數 (Visual Basic)。

泛型類型參數中的變異數

在 .NET Framework 4 和更新版本中,您可以啟用委派之間的隱含轉換,讓具有泛型型別參數所指定不同類型的泛型委派可以彼此指派,如果型別是依變數需要繼承自彼此。

若要啟用隱含轉換,您必須使用 inout 關鍵詞,明確地將委派中的泛型參數宣告為 covariant 或 contravariant。

下列程式代碼範例示範如何建立具有covariant泛型型別參數的委派。

' 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

如果您只使用變異數支援來比對方法簽章與委派類型,而且不使用 inout 關鍵詞,您可能會發現有時候您可以使用相同的 Lambda 表達式或方法具現化委派,但無法將一個委派指派給另一個委派。

在下列程式代碼範例中,SampleGenericDelegate(Of String)雖然 繼承 SampleGenericDelegate(Of Object),但無法明確轉換成 StringObject 。 您可以透過使用T關鍵字來標記泛型參數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

在 .NET Framework 中具有變異類型參數的泛型委派

.NET Framework 4 引進了數個現有泛型委派中泛型型別參數的變異數支援:

如需詳細資訊和範例,請參閱使用 Func 和 Action 泛型委派的變數(Visual Basic)。

在泛型委派中宣告變體類型參數

如果泛型委派具有 covariant 或 contravariant 泛型型別參數,它可以稱為 Variant 泛型委派

您可以在泛型委派中使用 out 關鍵詞宣告協變的泛型型別參數。 covariant 型別只能當做方法傳回型別使用,而不是做為方法自變數的類型。 下列程式代碼範例示範如何宣告 covariant 泛型委派。

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

您可以使用 關鍵詞,在泛型委派 in 中宣告泛型型別參數反變數。 反變數類型只能當做方法自變數的類型使用,而不是做為方法傳回型別。 下列程式代碼範例示範如何宣告反變數泛型委派。

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

這很重要

ByRef Visual Basic 中的參數無法標示為 variant。

您也可以在同一個委派中同時支援變數和共變數,但針對不同的類型參數。 下列範例會顯示這一點。

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

實例化和調用變體泛型委派

您可以實例化和叫用變形委派,就像實例化和叫用不變委派一樣。 在下列範例中,委派是由 Lambda 運算式具現化。

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

結合變異泛型委派

您不應該合併變體委派。 方法 Combine 不支援 Variant 委派轉換,而且預期委派的類型完全相同。 當您使用 Combine 方法(在 C# 和 Visual Basic 中)或使用 + 運算子(在 C# 中)結合委派時,可能會導致執行階段例外狀況,如下列程式代碼範例所示。

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)

實值型別和參考型別的泛型參數變異性

泛型型別參數的變異數僅支持參考型別。 例如, DVariant(Of Int)無法隱含轉換成 DVariant(Of Object)DVariant(Of Long),因為整數是實值型別。

下列範例示範泛型型別參數的型變不支援實值型別。

' 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

Visual Basic 中的寬鬆委派轉換

寬鬆的委派轉型能提供更大的靈活性,以便方法簽名與委派類型配對。 例如,當您將方法指派給委派時,它可讓您省略參數規格,並省略函式傳回值。 如需詳細資訊,請參閱 寬鬆委派轉換

另請參閱