Condividi tramite


Varianza dei delegati (Visual Basic)

.NET Framework 3.5 ha introdotto il supporto alla varianza per la corrispondenza delle firme dei metodi con i tipi di delegati in tutti i delegati in C# e Visual Basic. Ciò significa che è possibile assegnare a delegati non solo metodi con firme corrispondenti, ma anche metodi che restituiscono più tipi derivati (covarianza) o che accettano parametri con tipi meno derivati (controvarianza) rispetto a quelli specificati dal tipo delegato. Sono inclusi sia delegati generici che non generici.

Si consideri ad esempio il codice seguente, che ha due classi e due delegati: generico e non generico.

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

Quando si creano delegati dei SampleDelegate tipi o SampleDelegate(Of A, R) , è possibile assegnare uno dei metodi seguenti a tali delegati.

' 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

Nell'esempio di codice seguente viene illustrata la conversione implicita tra la firma del metodo e il tipo delegato.

' 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

Per altri esempi, vedere Uso della varianza nei delegati (Visual Basic) e Uso della varianza per i delegati generici Func e Action (Visual Basic).

Varianza nei parametri di tipo generico

In .NET Framework 4 e versioni successive è possibile abilitare la conversione implicita tra delegati, in modo che i delegati generici con tipi diversi specificati dai parametri di tipo generico possano essere assegnati tra loro, se i tipi vengono ereditati tra loro come richiesto dalla varianza.

Per abilitare la conversione implicita, è necessario dichiarare in modo esplicito i parametri generici in un delegato come covariante o controvariante usando la in parola chiave o out .

Nell'esempio di codice seguente viene illustrato come creare un delegato con un parametro di tipo generico covariante.

' 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

Se si usa solo il supporto della varianza per associare le firme dei metodi ai tipi delegati e non si usano le in parole chiave e out , talvolta è possibile creare istanze di delegati con espressioni o metodi lambda identici, ma non è possibile assegnare un delegato a un altro.

Nell'esempio SampleGenericDelegate(Of String) di codice seguente non può essere convertito in modo esplicito in SampleGenericDelegate(Of Object), anche se String eredita Object. È possibile risolvere questo problema contrassegnando il parametro generico T con la out parola chiave .

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

Delegati generici con parametri di tipo varianti in .NET Framework

.NET Framework 4 ha introdotto il supporto della varianza per i parametri di tipo generico in diversi delegati generici esistenti:

Per altre informazioni ed esempi, vedere Uso della varianza per Func e Action nei delegati generici (Visual Basic).

Dichiarazione dei parametri di tipo variante nei delegati generici

Se un delegato generico ha parametri di tipo generico covariante o controvarianti, può essere definito delegato generico variante.

È possibile dichiarare un parametro di tipo generico covariante in un delegato generico usando la out parola chiave . Il tipo covariante può essere usato solo come tipo restituito dal metodo e non come tipo di argomenti del metodo. Nell'esempio di codice seguente viene illustrato come dichiarare un delegato generico covariante.

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

È possibile dichiarare un parametro di tipo generico controvariante in un delegato generico usando la in parola chiave . Il tipo controvariante può essere utilizzato solo come tipo di argomenti del metodo e non come tipo di valore restituito del metodo. Nell'esempio di codice seguente viene illustrato come dichiarare un delegato generico controvariante.

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

Importante

ByRef I parametri in Visual Basic non possono essere contrassegnati come varianti.

È anche possibile supportare la varianza e la covarianza nello stesso delegato, ma per parametri di tipo diversi. Questo è illustrato nell'esempio seguente.

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

Creazione di istanze e invocazione di delegati generici varianti

È possibile creare un'istanza e richiamare delegati varianti esattamente come si crea un'istanza e si richiamano delegati invarianti. Nell'esempio seguente, il delegato è istanziato da un'espressione lambda.

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

Combinazione di delegati generici varianti

Non è consigliabile combinare delegati varianti. Il Combine metodo non supporta la conversione di delegati varianti e si aspetta che i delegati siano esattamente dello stesso tipo. Ciò può causare un'eccezione in fase di esecuzione quando si combinano delegati usando il Combine metodo (in C# e Visual Basic) o usando l'operatore + (in C#), come illustrato nell'esempio di codice seguente.

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)

Varianza nei parametri di tipo generico per i tipi valore e riferimento

La varianza per i parametri di tipo generico è supportata solo per i tipi di riferimento. Ad esempio, DVariant(Of Int)non può essere convertito in modo implicito in DVariant(Of Object) o DVariant(Of Long), perché integer è un tipo di valore.

Nell'esempio seguente viene illustrato che la varianza nei parametri di tipo generico non è supportata per i tipi valore.

' 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

Conversione rilassata del delegato in Visual Basic

La conversione flessibile di delegati consente una maggiore flessibilità nella corrispondenza tra le firme dei metodi e i tipi delegati. Ad esempio, consente di omettere le specifiche dei parametri e omettere i valori restituiti dalla funzione quando si assegna un metodo a un delegato. Per ulteriori informazioni, vedere Relaxed Delegate Conversion.

Vedere anche

  • Generics
  • Uso della varianza per i delegati generici Func e Action (Visual Basic)