.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)
に変換することはできませんが、 String
は Object
を継承します。 この問題を解決するには、ジェネリック パラメーター 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 では、いくつかの既存のジェネリック デリゲートでジェネリック型パラメーターの分散サポートが導入されました。
Action
System名前空間からのデリゲート (例: Action<T>とAction<T1,T2>Func
System名前空間からのデリゲート (例: Func<TResult>とFunc<T,TResult>Predicate<T> デリゲート
Comparison<T> デリゲート
詳細と例については、「 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 での緩やかなデリゲート変換
デリゲート変換を緩和すると、メソッドシグネチャとデリゲート型の照合をより柔軟に行えます。 たとえば、メソッドをデリゲートに割り当てるときに、パラメーターの指定を省略したり、関数の戻り値を省略したりできます。 詳細については、「 緩やかなデリゲート変換」を参照してください。
こちらも参照ください
.NET