Sdílet prostřednictvím


Vytváření variant obecných rozhraní (Visual Basic)

Parametry obecného typu můžete deklarovat v rozhraních jako kovariantní nebo kontravariantní. Kovariance umožňuje metodám rozhraní mít více odvozených návratových typů, než které jsou definovány parametry obecného typu. Kontravariance umožňuje metodám rozhraní mít typy argumentů, které jsou méně odvozené, než které jsou určeny obecnými parametry. Obecné rozhraní, které má kovariantní nebo kontravariantní parametry obecného typu, se nazývá varianta.

Poznámka:

Rozhraní .NET Framework 4 zavedlo podporu odchylek pro několik existujících obecných rozhraní. Seznam variant rozhraní v rozhraní .NET Framework naleznete v tématu Rozptyl v obecných rozhraních (Visual Basic).

Deklarace obecných rozhraní variant

Variantní obecná rozhraní můžete deklarovat pomocí inout klíčových slov pro parametry obecného typu.

Důležité

ByRef Parametry v jazyce Visual Basic nelze variantovat. Typy hodnot také nepodporují odchylku.

Kovariantní parametr obecného typu můžete deklarovat pomocí klíčového out slova. Kovariantní typ musí splňovat následující podmínky:

  • Typ se používá pouze jako návratový typ metod rozhraní a nepoužívá se jako typ argumentů metody. To je znázorněno v následujícím příkladu, ve kterém je typ R deklarován kovariant.

    Interface ICovariant(Of Out R)
        Function GetSomething() As R
        ' The following statement generates a compiler error.
        ' Sub SetSomething(ByVal sampleArg As R)
    End Interface
    

    Toto pravidlo má jednu výjimku. Pokud jako parametr metody máte kontravariantní obecný delegát, můžete tento typ použít jako parametr obecného typu pro delegáta. To je znázorněno typem R v následujícím příkladu. Další informace naleznete v tématu Rozptyl v delegátech (Visual Basic) a použití rozptylu pro func a action generic delegates (Visual Basic).

    Interface ICovariant(Of Out R)
        Sub DoSomething(ByVal callback As Action(Of R))
    End Interface
    
  • Typ se nepoužívá jako obecné omezení pro metody rozhraní. To je znázorněno v následujícím kódu.

    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
    

Parametr obecného typu můžete deklarovat kontravariant pomocí klíčového in slova. Kontravariantní typ lze použít pouze jako typ argumentů metody, a ne jako návratový typ metod rozhraní. Kontravariantní typ lze použít také pro obecná omezení. Následující kód ukazuje, jak deklarovat kontravariantní rozhraní a použít obecné omezení pro jednu z jeho metod.

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

Je také možné podporovat kovarianci i kontravarianci ve stejném rozhraní, ale pro různé parametry typu, jak je znázorněno v následujícím příkladu kódu.

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

V jazyce Visual Basic nemůžete deklarovat události v rozhraních variant bez zadání typu delegáta. Rozhraní variant také nemůže mít vnořené třídy, výčty nebo struktury, ale může mít vnořené rozhraní. To je znázorněno v následujícím kódu.

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

Implementace variantních obecných rozhraní

Ve třídách implementujete variantní obecná rozhraní pomocí stejné syntaxe, která se používá pro invariantní rozhraní. Následující příklad kódu ukazuje, jak implementovat kovariantní rozhraní v obecné třídě.

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

Třídy, které implementují variantní rozhraní, jsou invariantní. Představte si například následující kód.

 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

Rozšíření variantních obecných rozhraní

Když rozšíříte obecné rozhraní varianty, musíte použít in klíčová slova a out explicitně určit, zda odvozené rozhraní podporuje odchylku. Kompilátor neodvozuje odchylku od rozšířeného rozhraní. Představte si například následující rozhraní.

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

Invariant(Of T) V rozhraní je parametr T obecného typu invariantní, zatímco parametr IExtCovariant (Of Out T)typu je kovariantní, i když obě rozhraní rozšiřují stejné rozhraní. Stejné pravidlo se použije na parametry kontravariantního obecného typu.

Můžete vytvořit rozhraní, které rozšiřuje rozhraní, kde je parametr obecného typu T kovariantní, a rozhraní, kde je kontravariantní, pokud v rozšiřujícím rozhraní je parametr T obecného typu invariantní. To je znázorněno v následujícím příkladu kódu.

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

Pokud je však parametr T obecného typu deklarován kovariant v jednom rozhraní, nelze jej deklarovat kontravariant v rozšiřujícím rozhraní nebo naopak. To je znázorněno v následujícím příkladu kódu.

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

Zabránění nejednoznačnosti

Při implementaci obecných rozhraní variant může rozptyl někdy vést k nejednoznačnosti. Mělo by se tomu vyhnout.

Pokud například explicitně implementujete stejné obecné rozhraní variant s různými parametry obecného typu v jedné třídě, může vytvořit nejednoznačnost. Kompilátor v tomto případě nevygeneruje chybu, ale není určena, která implementace rozhraní bude vybrána za běhu. To může vést k drobným chybám v kódu. Uvažujte následující příklad kódu.

Poznámka:

Visual Option Strict OffBasic vygeneruje upozornění kompilátoru, pokud existuje nejednoznačná implementace rozhraní. Jazyk Option Strict OnVisual Basic vygeneruje chybu kompilátoru.

' 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

V tomto příkladu není určeno, jak pets.GetEnumerator se metoda mezi Cat a Dog. To může způsobit problémy v kódu.

Viz také