次の方法で共有


デリゲートの分散 (Visual Basic)

.NET Framework 3.5 では、C# と Visual Basic のすべてのデリゲートでメソッド シグネチャとデリゲート型を照合するための差異サポートが導入されました。 つまり、一致するシグネチャを持つメソッドだけでなく、より多くの派生型 (共変性) を返すメソッド、またはデリゲート型で指定されたよりも派生型 (反変性) が少ないパラメーターを受け入れるメソッドにもデリゲートを割り当てることができます。 これには、ジェネリック デリゲートと非ジェネリック デリゲートの両方が含まれます。

たとえば、ジェネリックと非ジェネリックの 2 つのクラスと 2 つのデリゲートを持つ次のコードを考えてみましょう。

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

SampleDelegate型またはSampleDelegate(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 Generic Delegate の分散の使用 (Visual Basic)」を参照してください。

ジェネリック型パラメーターの変性

.NET Framework 4 以降では、デリゲート間で暗黙的な変換を有効にして、ジェネリック型パラメーターで指定された異なる型を持つジェネリック デリゲートを相互に割り当てることができるようにすることができます(型が分散の必要に応じて相互に継承される場合)。

暗黙的な変換を有効にするには、 in キーワードまたは out キーワードを使用して、デリゲート内のジェネリック パラメーターを共変または反変として明示的に宣言する必要があります。

次のコード例は、共変ジェネリック型パラメーターを持つデリゲートを作成する方法を示しています。

' 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

分散のサポートのみを使用してメソッドシグネチャをデリゲート型と照合し、 in キーワードと out キーワードを使用しない場合は、同じラムダ式またはメソッドを使用してデリゲートをインスタンス化できますが、デリゲートを別のデリゲートに割り当てることができない場合があります。

次のコード例では、 SampleGenericDelegate(Of String) を明示的に SampleGenericDelegate(Of Object)に変換することはできませんが、 StringObjectを継承します。 この問題を解決するには、ジェネリック パラメーター Tout キーワードでマークします。

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 Generic Delegate の分散の使用 (Visual Basic)」を参照してください。

ジェネリック デリゲートでのバリアント型パラメーターの宣言

ジェネリック デリゲートに共変または反変のジェネリック型パラメーターがある場合は、 バリアント ジェネリック デリゲートと呼ばれます。

out キーワードを使用して、ジェネリック デリゲートで共変のジェネリック型パラメーターを宣言できます。 共変型は、メソッドの戻り値の型としてのみ使用でき、メソッド引数の型として使用することはできません。 次のコード例は、共変のジェネリック デリゲートを宣言する方法を示しています。

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

in キーワードを使用して、ジェネリック デリゲートでジェネリック型パラメーター反変を宣言できます。 反変型は、メソッドの戻り値の型としてではなく、メソッド引数の型としてのみ使用できます。 次のコード例は、反変ジェネリック デリゲートを宣言する方法を示しています。

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

Von Bedeutung

ByRef Visual Basic のパラメーターをバリアントとしてマークすることはできません。

同じデリゲートで分散と共分散の両方をサポートすることもできますが、型パラメーターが異なります。 これを次の例に示します。

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

バリアント ジェネリック デリゲートのインスタンス化と呼び出し

インバリアント デリゲートをインスタンス化して呼び出すのと同じように、バリアント デリゲートをインスタンス化して呼び出すことができます。 次の例では、デリゲートはラムダ式によってインスタンス化されます。

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

バリアント ジェネリック デリゲートの組み合わせ

バリアント デリゲートは結合しないでください。 Combine メソッドは、バリアント デリゲート変換をサポートせず、デリゲートがまったく同じ型であることが想定されています。 次のコード例に示すように、 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 での緩やかなデリゲート変換

デリゲート変換を緩和すると、メソッドシグネチャとデリゲート型の照合をより柔軟に行えます。 たとえば、メソッドをデリゲートに割り当てるときに、パラメーターの指定を省略したり、関数の戻り値を省略したりできます。 詳細については、「 緩やかなデリゲート変換」を参照してください。

こちらも参照ください