Variant generic Interfaces maken (Visual Basic)
U kunt algemene typeparameters in interfaces declareren als covariant of contravariant. Met covariantie kunnen interfacemethoden meer afgeleide retourtypen hebben dan die zijn gedefinieerd door de algemene typeparameters. Met Contravariantie kunnen interfacemethoden argumenttypen hebben die minder zijn afgeleid dan die zijn opgegeven door de algemene parameters. Een algemene interface met covariant of contravariant algemene typeparameters wordt variant genoemd.
Notitie
.NET Framework 4 heeft variantieondersteuning geïntroduceerd voor verschillende bestaande algemene interfaces. Zie Variantie in Generic Interfaces (Visual Basic) voor de lijst met variantinterfaces in .NET Framework.
Het declareren van algemene variantinterfaces
U kunt variant generic interfaces declareren met behulp van de in
en out
trefwoorden voor algemene typeparameters.
Belangrijk
ByRef
parameters in Visual Basic kunnen geen variant zijn. Waardetypen bieden ook geen ondersteuning voor variantie.
U kunt een covariant van een algemene typeparameter declareren met behulp van het out
trefwoord. Het covarianttype moet aan de volgende voorwaarden voldoen:
Het type wordt alleen gebruikt als een retourtype interfacemethoden en niet gebruikt als een type methodeargumenten. Dit wordt geïllustreerd in het volgende voorbeeld, waarin het type
R
covariant wordt gedeclareerd.Interface ICovariant(Of Out R) Function GetSomething() As R ' The following statement generates a compiler error. ' Sub SetSomething(ByVal sampleArg As R) End Interface
Er is één uitzondering op deze regel. Als u een algemene gemachtigde met contravariant als methodeparameter hebt, kunt u het type gebruiken als een algemene typeparameter voor de gemachtigde. Dit wordt geïllustreerd door het type
R
in het volgende voorbeeld. Zie Variantie in Gemachtigden (Visual Basic) en Variantie gebruiken voor Func en Action Generic Delegates (Visual Basic) voor meer informatie.Interface ICovariant(Of Out R) Sub DoSomething(ByVal callback As Action(Of R)) End Interface
Het type wordt niet gebruikt als een algemene beperking voor de interfacemethoden. Dit wordt geïllustreerd in de volgende code.
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
U kunt een algemeen type parameter contravariant declareren met behulp van het in
trefwoord. Het contravarianttype kan alleen worden gebruikt als een type methodeargumenten en niet als een retourtype interfacemethoden. Het type contravariant kan ook worden gebruikt voor algemene beperkingen. De volgende code laat zien hoe u een contravariant-interface declareert en een algemene beperking gebruikt voor een van de methoden.
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
Het is ook mogelijk om covariantie en contravariantie in dezelfde interface te ondersteunen, maar voor verschillende typeparameters, zoals wordt weergegeven in het volgende codevoorbeeld.
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 kunt u geen gebeurtenissen declareren in variantinterfaces zonder het type gedelegeerde op te geven. Een variantinterface kan ook geen geneste klassen, opsommingen of structuren hebben, maar wel geneste interfaces hebben. Dit wordt geïllustreerd in de volgende code.
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
Algemene variantinterfaces implementeren
U implementeert variant-algemene interfaces in klassen met behulp van dezelfde syntaxis die wordt gebruikt voor invariante interfaces. In het volgende codevoorbeeld ziet u hoe u een covariant-interface in een algemene klasse implementeert.
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
Klassen die variantinterfaces implementeren, zijn invariant. Denk bijvoorbeeld aan de volgende code.
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
Uitbreiding van algemene variantinterfaces
Wanneer u een algemene variantinterface uitbreidt, moet u de in
en out
trefwoorden gebruiken om expliciet op te geven of de afgeleide interface variantie ondersteunt. De compiler leidt niet af van de variantie van de interface die wordt uitgebreid. Denk bijvoorbeeld aan de volgende interfaces.
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
In de Invariant(Of T)
interface is de algemene typeparameter T
invariant, terwijl in IExtCovariant (Of Out T)
de typeparameter covariant is, hoewel beide interfaces dezelfde interface uitbreiden. Dezelfde regel wordt toegepast op parameters van het algemene type contravariant.
U kunt een interface maken die zowel de interface uitbreidt als de algemene typeparameter T
covariant is en de interface waar deze contravariant is als de parameter voor het algemene type T
invariant is in de uitbreidingsinterface. Dit wordt geïllustreerd in het volgende codevoorbeeld.
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
Als een algemene typeparameter T
echter covariant in één interface wordt gedeclareerd, kunt u deze niet declareren in de uitbreidingsinterface of omgekeerd. Dit wordt geïllustreerd in het volgende codevoorbeeld.
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
Dubbelzinnigheid vermijden
Wanneer u generieke variantinterfaces implementeert, kan afwijking soms leiden tot dubbelzinnigheid. Dit moet worden vermeden.
Als u bijvoorbeeld expliciet dezelfde algemene variantinterface met verschillende algemene typeparameters in één klasse implementeert, kan dit dubbelzinnigheid creëren. De compiler produceert in dit geval geen fout, maar wordt niet opgegeven welke interface-implementatie tijdens runtime wordt gekozen. Dit kan leiden tot subtiele fouten in uw code. Kijk eens naar het volgende codevoorbeeld.
Notitie
Met Option Strict Off
Visual Basic wordt een compilerwaarschuwing gegenereerd wanneer er sprake is van een dubbelzinnige interface-implementatie. Met Option Strict On
Visual Basic wordt een compilerfout gegenereerd.
' 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 dit voorbeeld wordt niet aangegeven hoe de pets.GetEnumerator
methode kiest tussen Cat
en Dog
. Dit kan problemen in uw code veroorzaken.