Compartir a través de


Creación de Interfaces Genéricas Variantes (Visual Basic)

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 R se 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 Interface
    

    Hay 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 R en 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 Interface
    
  • El 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.

Consulte también