Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Puede declarar parámetros de tipo genérico en interfaces como covariante o contravariante. La Covarianza permite que los métodos de interfaz tengan más tipos devueltos derivados que los definidos por los parámetros de tipo genérico. Contravariance permite que los métodos de interfaz tengan tipos de argumentos menos derivados que los especificados por los parámetros genéricos. Una interfaz genérica que tiene parámetros de tipo genérico covariante o contravariante se denomina variante.
Nota:
.NET Framework 4 introdujo compatibilidad de varianza para varias interfaces genéricas existentes. Para obtener la lista de las interfaces variant en .NET Framework, vea Varianza en interfaces genéricas (Visual Basic).
Declarar interfaces genéricas variantes
Puede declarar interfaces genéricas variantes mediante las in palabras clave y out para los parámetros de tipo genérico.
Importante
ByRef Los parámetros de Visual Basic no pueden ser variantes. Los tipos de valor tampoco admiten la varianza.
Puede declarar un parámetro de tipo genérico covariante mediante la out palabra clave . El tipo covariante debe cumplir las condiciones siguientes:
El tipo solo se utiliza como tipo de retorno en los métodos de una interfaz y no se utiliza como tipo de argumentos de método. Esto se ilustra en el ejemplo siguiente, en el que el tipo
Rse declara covariante.Interface ICovariant(Of Out R) Function GetSomething() As R ' The following statement generates a compiler error. ' Sub SetSomething(ByVal sampleArg As R) End InterfaceHay una excepción a esta regla. Si tiene un delegado genérico contravariante como parámetro de método, puede usar el tipo como parámetro de tipo genérico para el delegado. Esto se ilustra mediante el tipo
Ren el ejemplo siguiente. Para obtener más información, consulta Uso de la variación en Delegados (Visual Basic) y Uso de la variación para los delegados genéricos Func y Action (Visual Basic).Interface ICovariant(Of Out R) Sub DoSomething(ByVal callback As Action(Of R)) End InterfaceEl tipo no se usa como restricción genérica para los métodos de interfaz. Esto se muestra en el código siguiente.
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
Puede declarar un contravariante de parámetro de tipo genérico mediante la in palabra clave . El tipo contravariante solo se puede utilizar como tipo de argumentos en métodos y no como tipo de retorno en métodos de interfaz. El tipo contravariante también se puede usar para restricciones genéricas. En el código siguiente se muestra cómo declarar una interfaz contravariante y usar una restricción genérica para uno de sus 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
También es posible admitir covarianza y contravarianza en la misma interfaz, pero para parámetros de tipo diferentes, como se muestra en el ejemplo de código siguiente.
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
En Visual Basic, no se pueden declarar eventos en interfaces variantes sin especificar el tipo de delegado. Además, una interfaz variant no puede tener clases, enumeraciones o estructuras anidadas, pero puede tener interfaces anidadas. Esto se muestra en el código siguiente.
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
Implementar interfaces genéricas variantes
Las interfaces genéricas variantes se implementan en clases mediante la misma sintaxis que se usa para las interfaces invariables. En el ejemplo de código siguiente se muestra cómo implementar una interfaz covariante en una clase 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
Las clases que implementan interfaces variantes son invariables. Por ejemplo, considere el fragmento de código siguiente:
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
Extender interfaces genéricas variantes
Al extender una interfaz genérica variante, debe usar las in palabras clave y out para especificar explícitamente si la interfaz derivada admite varianza. El compilador no deduce la varianza de la interfaz que se está ampliando. Por ejemplo, considere las siguientes 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
En la Invariant(Of T) interfaz, el parámetro T de tipo genérico es invariable, mientras que en IExtCovariant (Of Out T)el parámetro de tipo es covariante, aunque ambas interfaces extienden la misma interfaz. La misma regla se aplica a los parámetros de tipo genérico contravariante.
Puede crear una interfaz que extienda la interfaz donde el parámetro T de tipo genérico es covariante y la interfaz donde es contravariante si en la interfaz de extensión el parámetro T de tipo genérico es invariable. Esto se muestra en el ejemplo de código siguiente.
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
Sin embargo, si un parámetro T de tipo genérico se declara covariante en una interfaz, no se puede declarar contravariante en la interfaz de extensión, o viceversa. Esto se muestra en el ejemplo de código siguiente.
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
Evitar ambigüedad
Al implementar interfaces genéricas variantes, la varianza a veces puede provocar ambigüedad. Esto debe evitarse.
Por ejemplo, si implementa explícitamente la misma interfaz genérica variante con distintos parámetros de tipo genérico en una clase, puede crear ambigüedad. El compilador no genera un error en este caso, pero no se especifica qué implementación de interfaz se elegirá en tiempo de ejecución. Esto podría provocar errores sutiles en el código. Observe el siguiente ejemplo de código.
Nota:
Con Option Strict Off, Visual Basic genera una advertencia del compilador cuando hay una implementación ambigua de interfaz. Con Option Strict On, Visual Basic genera un error del 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
En este ejemplo, no se especifica cómo elige el pets.GetEnumerator método entre Cat y Dog. Esto podría causar problemas en el código.