Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Você pode declarar parâmetros de tipo genérico em interfaces como covariantes ou contravariantes. A covariância permite que os métodos de interface tenham tipos de retorno mais derivados do que os definidos pelos parâmetros de tipo genérico. A contravariância permite que os métodos de interface tenham tipos de argumento menos derivados do que os especificados pelos parâmetros genéricos. Uma interface genérica que tem parâmetros de tipo genérico covariantes ou contravariantes é chamada de variante.
Observação
O .NET Framework 4 introduziu suporte de variação para várias interfaces genéricas existentes. Para obter a lista das interfaces variantes no .NET Framework, consulte Variação em Interfaces Genéricas (Visual Basic).
Declarando interfaces genéricas variantes
Você pode declarar interfaces genéricas variantes usando as palavras-chave in e out para parâmetros de tipo genérico.
Importante
ByRef os parâmetros no Visual Basic não podem ser variantes. Os tipos de valor também não dão suporte à variação.
Você pode declarar um covariante de parâmetro de tipo genérico usando a out palavra-chave. O tipo covariante deve atender às seguintes condições:
O tipo é usado apenas como um tipo de retorno de métodos de interface e não é usado como um tipo de argumentos de método. Isso é ilustrado no exemplo a seguir, no qual o tipo
Ré declarado covariante.Interface ICovariant(Of Out R) Function GetSomething() As R ' The following statement generates a compiler error. ' Sub SetSomething(ByVal sampleArg As R) End InterfaceHá uma exceção a essa regra. Se você tiver um delegado genérico contravariante como um parâmetro de método, você poderá usar o tipo como um parâmetro de tipo genérico para o delegado. Isso é ilustrado pelo tipo
Rno exemplo a seguir. Para obter mais informações, consulte Variação em Delegados (Visual Basic) e Usar Variação para Delegados Genéricos Func e Action (Visual Basic).Interface ICovariant(Of Out R) Sub DoSomething(ByVal callback As Action(Of R)) End InterfaceO tipo não é usado como uma restrição genérica para os métodos de interface. Isso é ilustrado no código a seguir.
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
Você pode declarar um parâmetro de tipo genérico contravariante usando a in palavra-chave. O tipo contravariante pode ser usado apenas como um tipo de argumentos de método e não como um tipo de retorno dos métodos de interface. O tipo contravariante também pode ser usado para restrições genéricas. O código a seguir mostra como declarar uma interface contravariante e usar uma restrição genérica para um de seus métodos.
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
Também é possível dar suporte à covariância e à contravariância na mesma interface, mas para parâmetros de tipo diferentes, conforme mostrado no exemplo de código a seguir.
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
No Visual Basic, você não pode declarar eventos em interfaces variantes sem especificar o tipo de delegado. Além disso, uma interface variante não pode ter classes aninhadas, enumerações ou estruturas, mas pode ter interfaces aninhadas. Isso é ilustrado no código a seguir.
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
Implementando interfaces genéricas variantes
Você implementa interfaces genéricas variantes em classes usando a mesma sintaxe usada para interfaces invariáveis. O exemplo de código a seguir mostra como implementar uma interface covariante em uma classe genérica.
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
Classes que implementam interfaces variantes são invariáveis. Por exemplo, considere o código a seguir.
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
Estendendo interfaces genéricas variantes
Ao estender uma interface genérica variante, você precisa usar as palavras-chave in e out para especificar explicitamente se a interface derivada suporta variação. O compilador não infere a variação da interface que está sendo estendida. Por exemplo, considere as interfaces a seguir.
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
Na interface Invariant(Of T), o parâmetro de tipo genérico T é invariável, enquanto na interface IExtCovariant (Of Out T), o parâmetro de tipo é covariante, embora ambas as interfaces estendam a mesma interface. A mesma regra é aplicada a parâmetros de tipo genérico contravariantes.
Você pode criar uma interface que estenda tanto a interface em que o parâmetro T de tipo genérico é covariante quanto a interface em que ele é contravariante, desde que, na interface resultante, o parâmetro T de tipo genérico seja invariável. Isso é ilustrado no exemplo de código a seguir.
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
No entanto, se um parâmetro T de tipo genérico for declarado covariante em uma interface, você não poderá declará-lo contravariante na interface de extensão ou vice-versa. Isso é ilustrado no exemplo de código a seguir.
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
Evitando ambiguidade
Quando você implementa interfaces genéricas variantes, a variação às vezes pode levar à ambiguidade. Isso deve ser evitado.
Por exemplo, se você implementar explicitamente a mesma interface genérica variante com diferentes parâmetros de tipo genérico em uma classe, ela poderá criar ambiguidade. O compilador não produz um erro nesse caso, mas não é especificado qual implementação de interface será escolhida em tempo de execução. Isso pode levar a bugs sutis em seu código. Considere o exemplo de código a seguir.
Observação
Com Option Strict Offo Visual Basic gera um aviso do compilador quando há uma implementação de interface ambígua. Com Option Strict Ono Visual Basic gera um erro do compilador.
' 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
Neste exemplo, não é especificado como o pets.GetEnumerator método escolhe entre Cat e Dog. Isso pode causar problemas em seu código.