Share via


委派中的變異數 (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),雖然 String 繼承 Object。 您可以使用 out 關鍵字標記泛型參數 T,修正這個問題。

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 中具有 Variant 型別參數的泛型委派

.NET Framework 4 推出差異支援,適用於數個現有泛型委派中的泛型型別參數:

如需詳細資訊及更多範例,請參閱針對 Func 與 Action 泛型委派使用變異數 (Visual Basic)

宣告泛型委派中的 Variant 型別參數

如果泛型委派具有 Covariant 或 Contravariant 泛型型別參數,它可以稱之為「Variant 泛型委派」

您可以使用 out 關鍵字將泛型委派中的泛型型別參數宣告為 Covariant。 Covariant 型別僅可用為方法傳回型別,不能用為方法引數的型別。 以下程式碼範例會示範如何宣告 Covariant 泛型委派。

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

您可以使用 in 關鍵字將泛型委派中的泛型型別參數宣告為 Contravariant。 Contravariant 型別僅可用為方法引數的型別,不能用為方法傳回型別。 以下程式碼範例會示範如何宣告 Contravariant 泛型委派。

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

重要

Visual Basic 中的 ByRef 參數不可標示為 Variant。

您也可以支援相同委派中不同型別參數的差異和共變數。 下列範例會顯示這一點。

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

具現化及叫用 Variant 泛型委派

您可以具現化及叫用 Variant 委派,一如您具現化及叫用非變異委派。 在下例中,委派是由 lambda 運算式具現化。

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

結合 Variant 泛型委派

您不應該組合 Variant 委派。 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 中的寬鬆委派轉換

寬鬆委派轉換可讓您更有彈性地比對方法簽章與委派型別。 例如,當您將方法指派給委派時,可讓您省略參數規格和省略函式傳回值。 如需詳細資訊,請參閱寬鬆委派轉換

另請參閱