Sdílet prostřednictvím


Vytváření Variant obecné rozhraní (C# a Visual Basic)

Můžete deklarovat parametry obecný typ rozhraní jako covariant nebo contravariant.Kovariance umožňuje více odvozené návratové typy než definované parametry obecný typ metody rozhraní.Contravariance umožňuje mít argument typy, které jsou odvozené nižší než určené obecné parametry metody rozhraní.Obecné rozhraní covariant nebo contravariant Parametry obecného typu se nazývá varianty.

[!POZNÁMKA]

.NET Framework 4 zavádí podporu odchylka pro několik stávající obecné rozhraní.Seznam variant rozhraní v.NET Framework, viz Odchylka v obecné rozhraní (C# a Visual Basic).

Deklarování variantu obecné rozhraní

Varianty obecné rozhraní můžete deklarovat pomocí in a out klíčová slova pro obecný typ parametrů.

Důležitá poznámkaDůležité

ByRefParametry v jazyce Visual Basic a ref a out parametry v C# nemůže být varianty.Typy hodnot také odchylka nepodporují.

Můžete deklarovat obecný typ parametru covariant pomocí out klíčové slovo.Covariant typu, musí splňovat následující podmínky:

  • Typ je použita pouze jako návratový typ metody rozhraní a není použit jako typ argumenty metody.Tento postup je znázorněn v následujícím příkladu, ve kterém typu R je deklarována jako covariant.

    Interface ICovariant(Of Out R)
        Function GetSomething() As R
        ' The following statement generates a compiler error.
        ' Sub SetSomething(ByVal sampleArg As R)
    End Interface
    
    interface ICovariant<out R>
    {
        R GetSomething();
        // The following statement generates a compiler error.
        // void SetSometing(R sampleArg);
    
    }
    

    Jedinou výjimkou tohoto pravidla je.Pokud máte obecná delegáta contravariant jako parametr metody, můžete jako obecný typ parametru typ pro delegáta.Tento postup je znázorněn podle typu R v následujícím příkladu.Další informace naleznete v tématu Rozptyl Delegáti (C# a Visual Basic) a Použití odchylky pro Func a akce obecný Delegáti (C# a Visual Basic).

    Interface ICovariant(Of Out R)
        Sub DoSomething(ByVal callback As Action(Of R))
    End Interface
    
    interface ICovariant<out R>
    {
        void DoSomething(Action<R> callback);
    }
    
  • Typ nepoužívá jako obecný omezení pro metody rozhraní.Tento postup je znázorněn 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 contstraints.
        ' Sub DoSomething(Of T As R)()
    End Interface
    
    interface ICovariant<out R>
    {
        // The following statement generates a compiler error
        // because you can use only contravariant or invariant types
        // in generic contstraints.
        // void DoSomething<T>() where T : R;
    }
    

Obecný typ parametru contravariant můžete deklarovat pomocí in klíčové slovo.Typ contravariant lze použít pouze jako typ argumenty metody a nikoli jako návratový typ metody rozhraní.Typ contravariant lze použít také pro obecné omezení.Následující kód ukazuje, jak deklarovat rozhraní contravariant a obecné omezení pro 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
interface IContravariant<in A>
{
    void SetSomething(A sampleArg);
    void DoSomething<T>() where T : A;
    // The following statement generates a compiler error.
    // A GetSomething();            
}

Je také možné podporovat kovariance a contravariance ve stejné rozhraní, ale pro jiný typ parametry, 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
interface IVariant<out R, in A>
{
    R GetSomething();
    void SetSomething(A sampleArg);
    R GetSetSometings(A sampleArg);
}

V jazyce Visual Basic nelze deklarovat bez určení typ delegáta události v rozhraní typu variant.Také varianty rozhraní vnořené třídy, výčty nebo struktury, ale jej můžete vnořovat rozhraní.Tento postup je znázorněn 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 rozhraní obecný varianty

Implementovat varianty obecné rozhraní tříd pomocí stejné syntaxe používaná pro výchozí rozhraní.Následující příklad kódu ukazuje, jak implementovat Obecná třída covariant rozhraní.

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
interface ICovariant<out R>
{
    R GetSomething();
}
class SampleImplementation<R> : ICovariant<R>
{
    public R GetSomething()
    {
        // Some code.
        return default(R);
    }
}

Třídy, které implementují rozhraní varianty jsou výchozí.Zvažte 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
// The interface is covariant.
ICovariant<Button> ibutton = new SampleImplementation<Button>();
ICovariant<Object> iobj = ibutton;

// The class is invariant.
SampleImplementation<Button> button = new SampleImplementation<Button>();
// The following statement generates a compiler error
// because classes are invariant.
// SampleImplementation<Object> obj = button;

Rozšíření obecné rozhraní varianty

Při rozšíření variant obecné rozhraní je nutné použít in a out klíčová slova explicitně určit, zda podporuje rozhraní odvozený rozptyl.Kompilátor neodvozují odchylka od rozhraní, která se rozšiřuje.Zvažte 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
interface ICovariant<out T> { }
interface IInvariant<T> : ICovariant<T> { }
interface IExtCovariant<out T> : ICovariant<T> { }

V IInvariant<T> (Invariant(Of T) v jazyce Visual Basic) rozhraní obecný typ parametru T je výchozí, že v IExtCovariant<out T> (IExtCovariant (Of Out T) v jazyce Visual Basic) parametru typ je covariant, ačkoli obě rozhraní rozšířit stejné rozhraní.Stejné pravidlo platí pro obecný typ parametry contravariant.

Můžete vytvořit rozhraní, které rozšiřuje rozhraní kde parametr typu obecného T je covariant a rozhraní, kde je contravariant v rozšíření rozhraní obecný typ parametru T je výchozí.Tento postup je znázorněn 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
interface ICovariant<out T> { }
interface IContravariant<in T> { }
interface IInvariant<T> : ICovariant<T>, IContravariant<T> { }

Však pokud obecný typ parametru T je deklarován covariant jedno rozhraní, nelze deklarovat jej contravariant rozšíření rozhraní nebo naopak.Tento postup je znázorněn 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
interface ICovariant<out T> { }
// The following statement generates a compiler error.
// interface ICoContraVariant<in T> : ICovariant<T> { }

Dd997386.collapse_all(cs-cz,VS.110).gifPředcházení nejednoznačnosti

Při implementaci rozhraní varianty obecný odchylka může někdy vést k nejednoznačnosti.To by se mělo zabránit.

Pokud implementujete explicitně varianty stejné obecné rozhraní s různými obecný typ parametry do jedné třídy, je vytvořit nejednoznačnosti.Kompilátor nevytvářejí chybu v tomto případě však není zadáno, implementaci rozhraní, které bude vybráno za běhu.To by mohlo vést k pravopisné chyby v kódu.Zvažte následující příklad kódu.

[!POZNÁMKA]

S Option Strict Off, Visual Basic generuje upozornění kompilátoru při implementaci rozhraní dvojznačný.S Option Strict On, Visual 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
// Simple class hierarchy.
class Animal { }
class Cat : Animal { }
class Dog : Animal { }

// This class introduces ambiguity
// because IEnumerable<out T> is covariant.
class Pets : IEnumerable<Cat>, IEnumerable<Dog>
{
    IEnumerator<Cat> IEnumerable<Cat>.GetEnumerator()
    {
        Console.WriteLine("Cat");
        // Some code.
        return null;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        // Some code.
        return null;
    }

    IEnumerator<Dog> IEnumerable<Dog>.GetEnumerator()
    {
        Console.WriteLine("Dog");
        // Some code.
        return null;
    }
}
class Program
{
    public static void Test()
    {
        IEnumerable<Animal> pets = new Pets();
        pets.GetEnumerator();
    }
}

V tomto příkladu nespecifikovaný jak na pets.GetEnumerator metodu zvolí mezi Cat a Dog.To může způsobit problémy v kódu.

Viz také

Referenční dokumentace

Použití odchylky pro Func a akce obecný Delegáti (C# a Visual Basic)

Koncepty

Odchylka v obecné rozhraní (C# a Visual Basic)