Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È possibile dichiarare parametri di tipo generico nelle interfacce come covariante o controvarianti. La Covarianza consente ai metodi di interfaccia di avere tipi restituiti più derivati rispetto a quelli definiti dai parametri di tipo generico. La controvarianza consente ai metodi di interfaccia di avere tipi di argomento meno derivati rispetto a quelli specificati dai parametri generici. Un'interfaccia generica con parametri di tipo generico covariante o controvarianti è denominata variant.
Annotazioni
.NET Framework 4 ha introdotto il supporto della varianza per diverse interfacce generiche esistenti. Per l'elenco delle interfacce varianti in .NET Framework, vedere Varianza in Interfacce generiche (Visual Basic).For the list of the variant interfaces in .NET Framework, see Variance in Generic Interfaces (Visual Basic).
Dichiarazione di interfacce generiche varianti
È possibile dichiarare interfacce generiche varianti usando le in parole chiave e out per i parametri di tipo generico.
Importante
ByRef I parametri in Visual Basic non possono essere varianti. Anche i tipi valore non supportano la varianza.
È possibile dichiarare un parametro di tipo generico covariante usando la out parola chiave . Il tipo covariante deve soddisfare le condizioni seguenti:
Il tipo viene utilizzato solo come tipo restituito di metodi di interfaccia e non utilizzato come tipo di argomenti del metodo. Questo è illustrato nell'esempio seguente, in cui il tipo
Rè dichiarato covariante.Interface ICovariant(Of Out R) Function GetSomething() As R ' The following statement generates a compiler error. ' Sub SetSomething(ByVal sampleArg As R) End InterfaceEsiste un'eccezione a questa regola. Se si dispone di un delegato generico controvariante come parametro del metodo, è possibile usare il tipo come parametro di tipo generico per il delegato. Questo è illustrato dal tipo
Rnell'esempio seguente. Per altre informazioni, vedere Varianza nei delegati (Visual Basic) e Uso della varianza per i delegati generici Func e Action (Visual Basic).Interface ICovariant(Of Out R) Sub DoSomething(ByVal callback As Action(Of R)) End InterfaceIl tipo non viene usato come vincolo generico per i metodi di interfaccia. Questo è illustrato nel codice seguente.
Interface ICovariant(Of Out R) ' The following statement generates a compiler error ' because you can use only contravariant or invariant types ' in generic constraints. ' Sub DoSomething(Of T As R)() End Interface
È possibile dichiarare un parametro di tipo generico controvariante usando la in parola chiave . Il tipo controvariante può essere utilizzato solo come tipo di argomenti del metodo e non come tipo restituito di metodi di interfaccia. Il tipo controvariante può essere usato anche per i vincoli generici. Il codice seguente illustra come dichiarare un'interfaccia controvariante e usare un vincolo generico per uno dei relativi metodi.
Interface IContravariant(Of In A)
Sub SetSomething(ByVal sampleArg As A)
Sub DoSomething(Of T As A)()
' The following statement generates a compiler error.
' Function GetSomething() As A
End Interface
È anche possibile supportare sia la covarianza che la controvarianza nella stessa interfaccia, ma per parametri di tipo diversi, come illustrato nell'esempio di codice seguente.
Interface IVariant(Of Out R, In A)
Function GetSomething() As R
Sub SetSomething(ByVal sampleArg As A)
Function GetSetSomething(ByVal sampleArg As A) As R
End Interface
In Visual Basic non è possibile dichiarare eventi nelle interfacce varianti senza specificare il tipo delegato. Inoltre, un'interfaccia variant non può avere classi annidate, enumerazioni o strutture, ma può avere interfacce annidate. Questo è illustrato nel codice seguente.
Interface ICovariant(Of Out R)
' The following statement generates a compiler error.
' Event SampleEvent()
' The following statement specifies the delegate type and
' does not generate an error.
Event AnotherEvent As EventHandler
' The following statements generate compiler errors,
' because a variant interface cannot have
' nested enums, classes, or structures.
'Enum SampleEnum : test : End Enum
'Class SampleClass : End Class
'Structure SampleStructure : Dim value As Integer : End Structure
' Variant interfaces can have nested interfaces.
Interface INested : End Interface
End Interface
Implementazione di interfacce generiche varianti
Le interfacce generiche varianti vengono implementate nelle classi usando la stessa sintassi usata per le interfacce invarianti. Nell'esempio di codice seguente viene illustrato come implementare un'interfaccia covariante in una classe generica.
Interface ICovariant(Of Out R)
Function GetSomething() As R
End Interface
Class SampleImplementation(Of R)
Implements ICovariant(Of R)
Public Function GetSomething() As R _
Implements ICovariant(Of R).GetSomething
' Some code.
End Function
End Class
Le classi che implementano interfacce varianti sono invarianti. Si consideri ad esempio il codice seguente.
The interface is covariant.
Dim ibutton As ICovariant(Of Button) =
New SampleImplementation(Of Button)
Dim iobj As ICovariant(Of Object) = ibutton
' The class is invariant.
Dim button As SampleImplementation(Of Button) =
New SampleImplementation(Of Button)
' The following statement generates a compiler error
' because classes are invariant.
' Dim obj As SampleImplementation(Of Object) = button
Estensione delle interfacce generiche varianti
Quando si estende un'interfaccia generica variante, è necessario usare le parole chiave in e out per specificare in modo esplicito se l'interfaccia derivata supporta la varianza. Il compilatore non deduce la varianza dall'interfaccia che viene estesa. Si considerino ad esempio le interfacce seguenti.
Interface ICovariant(Of Out T)
End Interface
Interface IInvariant(Of T)
Inherits ICovariant(Of T)
End Interface
Interface IExtCovariant(Of Out T)
Inherits ICovariant(Of T)
End Interface
Nell'interfaccia Invariant(Of T) il parametro T di tipo generico è invariante, mentre nel IExtCovariant (Of Out T)parametro di tipo è covariante, anche se entrambe le interfacce estendono la stessa interfaccia. La stessa regola viene applicata ai parametri di tipo generico controvariante.
È possibile creare un'interfaccia che estende sia l'interfaccia in cui il parametro T di tipo generico è covariante che l'interfaccia in cui è controvariante se nell'interfaccia di estensione il parametro di tipo generico T è invariante. Questo è illustrato nell'esempio di codice seguente.
Interface ICovariant(Of Out T)
End Interface
Interface IContravariant(Of In T)
End Interface
Interface IInvariant(Of T)
Inherits ICovariant(Of T), IContravariant(Of T)
End Interface
Tuttavia, se un parametro T di tipo generico è dichiarato covariante in un'interfaccia, non è possibile dichiararlo controvariante nell'interfaccia di estensione o viceversa. Questo è illustrato nell'esempio di codice seguente.
Interface ICovariant(Of Out T)
End Interface
' The following statements generate a compiler error.
' Interface ICoContraVariant(Of In T)
' Inherits ICovariant(Of T)
' End Interface
Evitare ambiguità
Quando si implementano interfacce generiche varianti, la varianza può talvolta causare ambiguità. Questa operazione deve essere evitata.
Ad esempio, se si implementa in modo esplicito la stessa interfaccia generica variant con parametri di tipo generici diversi in una classe, può creare ambiguità. Il compilatore non genera un errore in questo caso, ma non viene specificato quale implementazione dell'interfaccia verrà scelta in fase di esecuzione. Questo potrebbe causare bug sottili nel codice. Si consideri l'esempio di codice seguente.
Annotazioni
Con Option Strict Off, Visual Basic genera un avviso del compilatore quando è presente un'implementazione ambigua dell'interfaccia. Con Option Strict On, Visual Basic genera un errore del compilatore.
' Simple class hierarchy.
Class Animal
End Class
Class Cat
Inherits Animal
End Class
Class Dog
Inherits Animal
End Class
' This class introduces ambiguity
' because IEnumerable(Of Out T) is covariant.
Class Pets
Implements IEnumerable(Of Cat), IEnumerable(Of Dog)
Public Function GetEnumerator() As IEnumerator(Of Cat) _
Implements IEnumerable(Of Cat).GetEnumerator
Console.WriteLine("Cat")
' Some code.
End Function
Public Function GetEnumerator1() As IEnumerator(Of Dog) _
Implements IEnumerable(Of Dog).GetEnumerator
Console.WriteLine("Dog")
' Some code.
End Function
Public Function GetEnumerator2() As IEnumerator _
Implements IEnumerable.GetEnumerator
' Some code.
End Function
End Class
Sub Main()
Dim pets As IEnumerable(Of Animal) = New Pets()
pets.GetEnumerator()
End Sub
In questo esempio non viene specificato come il pets.GetEnumerator metodo sceglie tra Cat e Dog. Ciò potrebbe causare problemi nel codice.
Vedere anche
- Varianza nelle interfacce generiche (Visual Basic)
- Uso della varianza per i delegati generici Func e Action (Visual Basic)