Covariance et contravariance dans les génériquesCovariance and Contravariance in Generics

La covariance et la contravariance sont des termes qui font référence à la possibilité d’utiliser un type plus dérivé (plus spécifique) ou moins dérivé (moins spécifique) que celui spécifié à l’origine.Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Les paramètres de type générique prennent en charge la covariance et la contravariance afin de fournir une meilleure flexibilité dans l'assignation et l'utilisation des types génériques.Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types. Lorsque vous faites référence à un système de type, la covariance, la contravariance et l'invariance ont les définitions suivantes.When you are referring to a type system, covariance, contravariance, and invariance have the following definitions. Les exemples supposent qu'une classe de base est nommée Base et qu'une classe dérivée est nommée Derived.The examples assume a base class named Base and a derived class named Derived.

  • Covariance

    Vous permet d'utiliser un type plus dérivé que celui spécifié à l'origine.Enables you to use a more derived type than originally specified.

    Vous pouvez assigner une instance de IEnumerable<Derived> (IEnumerable(Of Derived) en Visual Basic) à une variable de type IEnumerable<Base>.You can assign an instance of IEnumerable<Derived> (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable<Base>.

  • Contravariance

    Vous permet d'utiliser un type plus générique (moins dérivé) que celui spécifié à l'origine.Enables you to use a more generic (less derived) type than originally specified.

    Vous pouvez assigner une instance de Action<Base> (Action(Of Base) en Visual Basic) à une variable de type Action<Derived>.You can assign an instance of Action<Base> (Action(Of Base) in Visual Basic) to a variable of type Action<Derived>.

  • Invariance

    Signifie que vous pouvez utiliser uniquement le type spécifié à l'origine ; pour un paramètre de type générique indifférent, il n'est ni covariant ni contravariant.Means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.

    Vous ne pouvez pas attribuer une instance de List<Base> (List(Of Base) en Visual Basic) à une variable de type List<Derived> et inversement.You cannot assign an instance of List<Base> (List(Of Base) in Visual Basic) to a variable of type List<Derived> or vice versa.

Les paramètres de type covariant vous permettent d'effectuer des assignations très similaires au Polymorphisme ordinaire, comme indiqué dans le code suivant.Covariant type parameters enable you to make assignments that look much like ordinary Polymorphism, as shown in the following code.

IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
Dim d As IEnumerable(Of Derived) = New List(Of Derived)
Dim b As IEnumerable(Of Base) = d

La classe List<T> implémente l'interface générique IEnumerable<T> , donc List<Derived> (List(Of Derived) en Visual Basic) implémente IEnumerable<Derived>.The List<T> class implements the IEnumerable<T> interface, so List<Derived> (List(Of Derived) in Visual Basic) implements IEnumerable<Derived>. Le paramètre de type covariant fait le reste.The covariant type parameter does the rest.

La contravariance, en revanche, paraît peu intuitive.Contravariance, on the other hand, seems counterintuitive. L'exemple suivant crée un délégué de type Action<Base> (Action(Of Base) en Visual Basic), puis assigne ce délégué à une variable de type Action<Derived>.The following example creates a delegate of type Action<Base> (Action(Of Base) in Visual Basic), and then assigns that delegate to a variable of type Action<Derived>.

Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
d(new Derived());
Dim b As Action(Of Base) = Sub(target As Base) 
                               Console.WriteLine(target.GetType().Name)
                           End Sub
Dim d As Action(Of Derived) = b
d(New Derived())

Cela peut paraître rétrograde, mais c'est le code de type sécurisé qui est compilé et exécuté.This seems backward, but it is type-safe code that compiles and runs. L'expression lambda correspond au délégué auquel elle est assignée, elle définit donc une méthode qui prend un paramètre de type Base et n'a aucune valeur de retour.The lambda expression matches the delegate it is assigned to, so it defines a method that takes one parameter of type Base and that has no return value. Le délégué résultant peut être assigné à une variable de type Action<Derived> parce que le paramètre de type T du délégué Action<T> est contravariant.The resulting delegate can be assigned to a variable of type Action<Derived> because the type parameter T of the Action<T> delegate is contravariant. Le code est de type sécurisé parce que T spécifie un type de paramètre.The code is type-safe because T specifies a parameter type. Lorsque le délégué de type Action<Base> est appelé comme s'il était de type Action<Derived>, son argument doit être de type Derived.When the delegate of type Action<Base> is invoked as if it were a delegate of type Action<Derived>, its argument must be of type Derived. Cet argument peut toujours être passé sans risque à la méthode sous-jacente, parce que le paramètre de la méthode est de type Base.This argument can always be passed safely to the underlying method, because the method's parameter is of type Base.

En général, un paramètre de type covariant peut être utilisé comme type de retour d'un délégué et les paramètres de type contravariant peuvent être utilisés comme types de paramètres.In general, a covariant type parameter can be used as the return type of a delegate, and contravariant type parameters can be used as parameter types. Pour une interface, les paramètres de type covariant peuvent être utilisés comme types de retour des méthodes de l'interface et les paramètres de type contravariant peuvent être utilisés comme types de paramètres des méthodes de l'interface.For an interface, covariant type parameters can be used as the return types of the interface's methods, and contravariant type parameters can be used as the parameter types of the interface's methods.

La covariance et la contravariance sont désignées collectivement sous le nom de variation.Covariance and contravariance are collectively referred to as variance. Un paramètre de type générique qui n'est marqué ni comme étant covariant, ni comme étant contravariant, est appelé indifférent.A generic type parameter that is not marked covariant or contravariant is referred to as invariant. Récapitulatif des informations relatives à la variance dans le common language runtime :A brief summary of facts about variance in the common language runtime:

  • Dans .NET Framework 4, les paramètres de type variant sont limités aux types d’interfaces génériques et aux types délégués génériques.In the .NET Framework 4, variant type parameters are restricted to generic interface and generic delegate types.

  • Un type d'interface générique ou un type délégué générique peut avoir des paramètres de type covariant et contravariant.A generic interface or generic delegate type can have both covariant and contravariant type parameters.

  • La variance s'applique uniquement aux types référence ; si vous spécifiez un type valeur pour un paramètre de type variant, ce paramètre de type est indifférent pour le type construit résultant.Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

  • La variance ne s'applique pas à la combinaison de délégués.Variance does not apply to delegate combination. Autrement dit, avec deux délégués de types Action<Derived> et Action<Base> (Action(Of Derived) et Action(Of Base) en Visual Basic), il n'est pas possible de combiner le deuxième délégué avec le premier, même si le résultat sera de type sécurisé.That is, given two delegates of types Action<Derived> and Action<Base> (Action(Of Derived) and Action(Of Base) in Visual Basic), you cannot combine the second delegate with the first although the result would be type safe. La variance permet au deuxième délégué d'être assigné à une variable de type Action<Derived>, mais les délégués peuvent uniquement être combinés si leurs types correspondent exactement.Variance allows the second delegate to be assigned to a variable of type Action<Derived>, but delegates can combine only if their types match exactly.

Les sous-sections suivantes décrivent en détail les paramètres de type covariant et contravariant :The following subsections describe covariant and contravariant type parameters in detail:

Interfaces génériques avec paramètres de type covariantGeneric Interfaces with Covariant Type Parameters

À compter de .NET Framework 4, plusieurs interfaces génériques ont des paramètres de type covariant, par exemple IEnumerable<T>, IEnumerator<T>, IQueryable<T> et IGrouping<TKey,TElement>.Starting with the .NET Framework 4, several generic interfaces have covariant type parameters; for example: IEnumerable<T>, IEnumerator<T>, IQueryable<T>, and IGrouping<TKey,TElement>. Tous les paramètres de type de ces interfaces sont covariants, les paramètres de type sont donc uniquement utilisés pour les types de retour des membres.All the type parameters of these interfaces are covariant, so the type parameters are used only for the return types of the members.

L'exemple suivant illustre les paramètres de type covariant.The following example illustrates covariant type parameters. L'exemple définit deux types : Base a une méthode statique nommée PrintBases qui prend un IEnumerable<Base> (IEnumerable(Of Base) en Visual Basic) et imprime les éléments.The example defines two types: Base has a static method named PrintBases that takes an IEnumerable<Base> (IEnumerable(Of Base) in Visual Basic) and prints the elements. Derived hérite de Base.Derived inherits from Base. L'exemple crée un List<Derived> vide (List(Of Derived) en Visual Basic) et montre que ce type peut être passé à PrintBases et assigné à une variable de type IEnumerable<Base> sans cast.The example creates an empty List<Derived> (List(Of Derived) in Visual Basic) and demonstrates that this type can be passed to PrintBases and assigned to a variable of type IEnumerable<Base> without casting. List<T> implémente IEnumerable<T>, qui a un paramètre de type covariant unique.List<T> implements IEnumerable<T>, which has a single covariant type parameter. Le paramètre de type covariant est la raison pour laquelle une instance de IEnumerable<Derived> peut être utilisée au lieu de IEnumerable<Base>.The covariant type parameter is the reason why an instance of IEnumerable<Derived> can be used instead of IEnumerable<Base>.

using System;
using System.Collections.Generic;

class Base
{
    public static void PrintBases(IEnumerable<Base> bases)
    {
        foreach(Base b in bases)
        {
            Console.WriteLine(b);
        }
    }
}

class Derived : Base
{
    public static void Main()
    {
        List<Derived> dlist = new List<Derived>();

        Derived.PrintBases(dlist);
        IEnumerable<Base> bIEnum = dlist;
    }
}
Imports System.Collections.Generic

Class Base
    Public Shared Sub PrintBases(ByVal bases As IEnumerable(Of Base))
        For Each b As Base In bases
            Console.WriteLine(b)
        Next
    End Sub    
End Class

Class Derived
    Inherits Base

    Shared Sub Main()
        Dim dlist As New List(Of Derived)()

        Derived.PrintBases(dlist)
        Dim bIEnum As IEnumerable(Of Base) = dlist
    End Sub
End Class

Retour au débutBack to top

Interfaces génériques avec paramètres de type générique contravariantGeneric Interfaces with Contravariant Generic Type Parameters

À compter de .NET Framework 4, plusieurs interfaces génériques ont des paramètres de type contravariant, par exemple IComparer<T>, IComparable<T> et IEqualityComparer<T>.Starting with the .NET Framework 4, several generic interfaces have contravariant type parameters; for example: IComparer<T>, IComparable<T>, and IEqualityComparer<T>. Ces interfaces ont des paramètres de type contravariant uniquement, par conséquent, les paramètres de type sont utilisés uniquement comme types de paramètre dans les membres des interfaces.These interfaces have only contravariant type parameters, so the type parameters are used only as parameter types in the members of the interfaces.

L'exemple suivant illustre les paramètres de type contravariant.The following example illustrates contravariant type parameters. L'exemple définit une classe abstraite (MustInherit dans Visual Basic) Shape avec une propriété Area .The example defines an abstract (MustInherit in Visual Basic) Shape class with an Area property. L'exemple définit également une classe ShapeAreaComparer qui implémente IComparer<Shape> (IComparer(Of Shape) dans Visual Basic).The example also defines a ShapeAreaComparer class that implements IComparer<Shape> (IComparer(Of Shape) in Visual Basic). L'implémentation de la méthode IComparer<T>.Compare est basée sur la valeur de la propriété Area , de sorte que ShapeAreaComparer peut être utilisé pour trier des objets Shape par zone.The implementation of the IComparer<T>.Compare method is based on the value of the Area property, so ShapeAreaComparer can be used to sort Shape objects by area.

La classe Circle hérite de Shape et remplace Area.The Circle class inherits Shape and overrides Area. L'exemple crée un SortedSet<T> d'objets Circle , à l'aide d'un constructeur qui accepte un IComparer<Circle> (IComparer(Of Circle) dans Visual Basic).The example creates a SortedSet<T> of Circle objects, using a constructor that takes an IComparer<Circle> (IComparer(Of Circle) in Visual Basic). Toutefois, au lieu de passer un IComparer<Circle>, l'exemple passe un objet ShapeAreaComparer qui implémente IComparer<Shape>.However, instead of passing an IComparer<Circle>, the example passes a ShapeAreaComparer object, which implements IComparer<Shape>. L'exemple peut passer un comparateur d'un type moins dérivé (Shape) lorsque le code appelle un comparateur d'un type plus dérivé (Circle), parce que le paramètre de type de l'interface générique IComparer<T> est contravariant.The example can pass a comparer of a less derived type (Shape) when the code calls for a comparer of a more derived type (Circle), because the type parameter of the IComparer<T> generic interface is contravariant.

Lorsqu'un nouvel objet Circle est ajouté au SortedSet<Circle>, la méthode IComparer<Shape>.Compare (méthodeIComparer(Of Shape).Compare dans Visual Basic) de l'objet ShapeAreaComparer est appelée chaque fois que le nouvel élément est comparé à un élément existant.When a new Circle object is added to the SortedSet<Circle>, the IComparer<Shape>.Compare method (IComparer(Of Shape).Compare method in Visual Basic) of the ShapeAreaComparer object is called each time the new element is compared to an existing element. Le type de paramètre de la méthode (Shape) étant moins dérivé que le type passé (Circle), l'appel garantit la cohérence des types.The parameter type of the method (Shape) is less derived than the type that is being passed (Circle), so the call is type safe. La contravariance permet à ShapeAreaComparer de trier une collection d'un type unique, ainsi qu'une collection mixte de types, qui dérivent de Shape.Contravariance enables ShapeAreaComparer to sort a collection of any single type, as well as a mixed collection of types, that derive from Shape.

using System;
using System.Collections.Generic;

abstract class Shape
{
    public virtual double Area { get { return 0; }}
}

class Circle : Shape
{
    private double r;
    public Circle(double radius) { r = radius; }
    public double Radius { get { return r; }}
    public override double Area { get { return Math.PI * r * r; }}
}

class ShapeAreaComparer : System.Collections.Generic.IComparer<Shape>
{
    int IComparer<Shape>.Compare(Shape a, Shape b) 
    { 
        if (a == null) return b == null ? 0 : -1;
        return b == null ? 1 : a.Area.CompareTo(b.Area);
    }
}

class Program
{
    static void Main()
    {
        // You can pass ShapeAreaComparer, which implements IComparer<Shape>,
        // even though the constructor for SortedSet<Circle> expects 
        // IComparer<Circle>, because type parameter T of IComparer<T> is
        // contravariant.
        SortedSet<Circle> circlesByArea = 
            new SortedSet<Circle>(new ShapeAreaComparer()) 
                { new Circle(7.2), new Circle(100), null, new Circle(.01) };

        foreach (Circle c in circlesByArea)
        {
            Console.WriteLine(c == null ? "null" : "Circle with area " + c.Area);
        }
    }
}

/* This code example produces the following output:

null
Circle with area 0.000314159265358979
Circle with area 162.860163162095
Circle with area 31415.9265358979
 */
Imports System.Collections.Generic

MustInherit Class Shape
    Public MustOverride ReadOnly Property Area As Double
End Class

Class Circle
    Inherits Shape

    Private r As Double 
    Public Sub New(ByVal radius As Double)
        r = radius
    End Sub 
    Public ReadOnly Property Radius As Double
        Get
            Return r
        End Get
    End Property
    Public Overrides ReadOnly Property Area As Double
        Get
            Return Math.Pi * r * r
        End Get
    End Property
End Class

Class ShapeAreaComparer
    Implements System.Collections.Generic.IComparer(Of Shape)

    Private Function AreaComparer(ByVal a As Shape, ByVal b As Shape) As Integer _
            Implements System.Collections.Generic.IComparer(Of Shape).Compare
        If a Is Nothing Then Return If(b Is Nothing, 0, -1)
        Return If(b Is Nothing, 1, a.Area.CompareTo(b.Area))
    End Function
End Class

Class Program
    Shared Sub Main()
        ' You can pass ShapeAreaComparer, which implements IComparer(Of Shape),
        ' even though the constructor for SortedSet(Of Circle) expects 
        ' IComparer(Of Circle), because type parameter T of IComparer(Of T)
        ' is contravariant.
        Dim circlesByArea As New SortedSet(Of Circle)(New ShapeAreaComparer()) _
            From { New Circle(7.2), New Circle(100), Nothing, New Circle(.01) }

        For Each c As Circle In circlesByArea
            Console.WriteLine(If(c Is Nothing, "Nothing", "Circle with area " & c.Area))
        Next
    End Sub
End Class

' This code example produces the following output:
'
'Nothing
'Circle with area 0.000314159265358979
'Circle with area 162.860163162095
'Circle with area 31415.9265358979

Retour au débutBack to top

Délégués génériques avec paramètres de type variantGeneric Delegates with Variant Type Parameters

Dans .NET Framework 4, les délégués génériques Func, tels que Func<T,TResult>, ont des types de retours covariants et des types de paramètres contravariants.In the .NET Framework 4, the Func generic delegates, such as Func<T,TResult>, have covariant return types and contravariant parameter types. Les délégués génériques Action , tels que Action<T1,T2>, ont des types de paramètres contravariants.The Action generic delegates, such as Action<T1,T2>, have contravariant parameter types. Cela signifie que les délégués peuvent être assignés à des variables avec des types de paramètres plus dérivés et (dans le cas des délégués génériques Func ) des types de retour moins dérivés.This means that the delegates can be assigned to variables that have more derived parameter types and (in the case of the Func generic delegates) less derived return types.

Notes

Le dernier paramètre de type générique des délégués génériques Func spécifie le type de la valeur de retour dans la signature du délégué.The last generic type parameter of the Func generic delegates specifies the type of the return value in the delegate signature. Il est covariant (mot cléout ), alors que les autres paramètres de type générique sont contravariants (mot cléin ).It is covariant (out keyword), whereas the other generic type parameters are contravariant (in keyword).

Le code suivant illustre ce comportement :The following code illustrates this. La première partie du code définit une classe nommée Base, une classe nommée Derived qui hérite de Base, et une autre classe avec une méthode static (Shared en Visual Basic) nommée MyMethod.The first piece of code defines a class named Base, a class named Derived that inherits Base, and another class with a static method (Shared in Visual Basic) named MyMethod. La méthode prend une instance de Base et retourne une instance de Derived.The method takes an instance of Base and returns an instance of Derived. (Si l'argument est une instance de Derived, MyMethod le retourne ; si l'argument est une instance de Base, MyMethod retourne une nouvelle instance de Derived.) Dans Main(), l'exemple crée une instance de Func<Base, Derived> (Func(Of Base, Derived) en Visual Basic) qui représente MyMethod, puis la stocke dans la variable f1.(If the argument is an instance of Derived, MyMethod returns it; if the argument is an instance of Base, MyMethod returns a new instance of Derived.) In Main(), the example creates an instance of Func<Base, Derived> (Func(Of Base, Derived) in Visual Basic) that represents MyMethod, and stores it in the variable f1.

public class Base {}
public class Derived : Base {}

public class Program
{
    public static Derived MyMethod(Base b)
    {
        return b as Derived ?? new Derived();
    }

    static void Main() 
    {
        Func<Base, Derived> f1 = MyMethod;
Public Class Base 
End Class
Public Class Derived
    Inherits Base
End Class

Public Class Program
    Public Shared Function MyMethod(ByVal b As Base) As Derived 
        Return If(TypeOf b Is Derived, b, New Derived())
    End Function

    Shared Sub Main() 
        Dim f1 As Func(Of Base, Derived) = AddressOf MyMethod

La deuxième partie du code indique que le délégué peut être assigné à une variable de type Func<Base, Base> (Func(Of Base, Base) en Visual Basic), car le type de retour est covariant.The second piece of code shows that the delegate can be assigned to a variable of type Func<Base, Base> (Func(Of Base, Base) in Visual Basic), because the return type is covariant.

// Covariant return type.
Func<Base, Base> f2 = f1;
Base b2 = f2(new Base());
' Covariant return type.
Dim f2 As Func(Of Base, Base) = f1
Dim b2 As Base = f2(New Base())

La troisième partie du code indique que le délégué peut être assigné à une variable de type Func<Derived, Derived> (Func(Of Derived, Derived) en Visual Basic), car le type de paramètre est contravariant.The third piece of code shows that the delegate can be assigned to a variable of type Func<Derived, Derived> (Func(Of Derived, Derived) in Visual Basic), because the parameter type is contravariant.

// Contravariant parameter type.
Func<Derived, Derived> f3 = f1;
Derived d3 = f3(new Derived());
' Contravariant parameter type.
Dim f3 As Func(Of Derived, Derived) = f1
Dim d3 As Derived = f3(New Derived())

La dernière partie du code indique que le délégué peut être assigné à une variable de type Func<Derived, Base> (Func(Of Derived, Base) en Visual Basic), ce qui combine les effets du type de paramètre contravariant et du type de valeur de retour covariant.The final piece of code shows that the delegate can be assigned to a variable of type Func<Derived, Base> (Func(Of Derived, Base) in Visual Basic), combining the effects of the contravariant parameter type and the covariant return type.

// Covariant return type and contravariant parameter type.
Func<Derived, Base> f4 = f1;
Base b4 = f4(new Derived());
' Covariant return type and contravariant parameter type.
Dim f4 As Func(Of Derived, Base) = f1
Dim b4 As Base = f4(New Derived())

Variance dans les délégués génériques et non génériquesVariance in Generic and Non-Generic Delegates

Dans le code précédent, la signature de MyMethod correspond exactement à la signature du délégué générique construit : Func<Base, Derived> (Func(Of Base, Derived) en Visual Basic).In the preceding code, the signature of MyMethod exactly matches the signature of the constructed generic delegate: Func<Base, Derived> (Func(Of Base, Derived) in Visual Basic). L'exemple montre que ce délégué générique peut être stocké dans des variables ou des paramètres de méthode qui ont des types de paramètres plus dérivés et des types de retour moins dérivés, tant que tous les types délégués sont construits à partir du type délégué générique Func<T,TResult>.The example shows that this generic delegate can be stored in variables or method parameters that have more derived parameter types and less derived return types, as long as all the delegate types are constructed from the generic delegate type Func<T,TResult>.

Ceci est un point important.This is an important point. Les effets de la covariance et de la contravariance dans les paramètres de type des délégués génériques sont semblables aux effets de la covariance et de la contravariance dans la liaison de délégués ordinaire (consultez Variance dans les délégués (C#) et Variance dans les délégués (Visual Basic)).The effects of covariance and contravariance in the type parameters of generic delegates are similar to the effects of covariance and contravariance in ordinary delegate binding (see Variance in Delegates (C#) and Variance in Delegates (Visual Basic)). Toutefois, la variance dans la liaison de délégués fonctionne avec tous les types délégués, et pas seulement les types délégués génériques qui ont des paramètres de type variant.However, variance in delegate binding works with all delegate types, not just with generic delegate types that have variant type parameters. En outre, la variance dans la liaison de délégués permet de lier une méthode à tout délégué disposant de types de paramètres plus restrictifs et d'un type de retour moins restrictif, alors que l'assignation de délégués génériques fonctionne uniquement si les deux types délégués sont construits à partir de la même définition de type générique.Furthermore, variance in delegate binding enables a method to be bound to any delegate that has more restrictive parameter types and a less restrictive return type, whereas the assignment of generic delegates works only if both delegate types are constructed from the same generic type definition.

L'exemple suivant indique les effets combinés de la variance dans la liaison de délégués et de la variance dans les paramètres de type générique.The following example shows the combined effects of variance in delegate binding and variance in generic type parameters. L'exemple définit une hiérarchie de type qui inclut trois types, du moins dérivé (Type1) au plus dérivé (Type3).The example defines a type hierarchy that includes three types, from least derived (Type1) to most derived (Type3). La variance dans la liaison de délégués ordinaire est utilisée pour lier une méthode avec le type de paramètre Type1 et le type de retour Type3 à un délégué générique avec le type de paramètre Type2 et le type de retour Type2.Variance in ordinary delegate binding is used to bind a method with a parameter type of Type1 and a return type of Type3 to a generic delegate with a parameter type of Type2 and a return type of Type2. Le délégué générique résultant est ensuite assigné à une autre variable dont le type délégué générique a un paramètre de type Type3 et le type de retour Type1, à l'aide de la covariance et de la contravariance de paramètres de type générique.The resulting generic delegate is then assigned to another variable whose generic delegate type has a parameter of type Type3 and a return type of Type1, using the covariance and contravariance of generic type parameters. La deuxième assignation requiert que le type de variable et le type délégué soient construits à partir de la même définition de type générique, dans ce cas, Func<T,TResult>.The second assignment requires both the variable type and the delegate type to be constructed from the same generic type definition, in this case, Func<T,TResult>.

using System;

public class Type1 {}
public class Type2 : Type1 {}
public class Type3 : Type2 {}

public class Program
{
    public static Type3 MyMethod(Type1 t)
    {
        return t as Type3 ?? new Type3();
    }

    static void Main() 
    {
        Func<Type2, Type2> f1 = MyMethod;

        // Covariant return type and contravariant parameter type.
        Func<Type3, Type1> f2 = f1;
        Type1 t1 = f2(new Type3());
    }
}
Public Class Type1 
End Class
Public Class Type2
    Inherits Type1
End Class
Public Class Type3
    Inherits Type2
End Class

Public Class Program
    Public Shared Function MyMethod(ByVal t As Type1) As Type3
        Return If(TypeOf t Is Type3, t, New Type3())
    End Function

    Shared Sub Main() 
        Dim f1 As Func(Of Type2, Type2) = AddressOf MyMethod

        ' Covariant return type and contravariant parameter type.
        Dim f2 As Func(Of Type3, Type1) = f1
        Dim t1 As Type1 = f2(New Type3())
    End Sub
End Class

Retour au débutBack to top

Définition d'interfaces et de délégués génériques variantsDefining Variant Generic Interfaces and Delegates

À compter de .NET Framework 4, Visual Basic et Visual C# ont des mots clés qui vous permettent de marquer les paramètres de type générique des interfaces et des délégués comme covariants ou contravariants.Starting with the .NET Framework 4, Visual Basic and C# have keywords that enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant.

Notes

Depuis le .NET Framework version 2.0, le Common Language Runtime prend en charge les annotations de variance sur les paramètres de type générique.Starting with the .NET Framework version 2.0, the common language runtime supports variance annotations on generic type parameters. Avant .NET Framework 4, la seule méthode pour définir une classe générique avec ces annotations consistait à utiliser le langage MSIL (Microsoft Intermediate Language), en compilant la classe avec Ilasm.exe (Assembleur IL) ou en l’émettant dans un assembly dynamique.Prior to the .NET Framework 4, the only way to define a generic class that has these annotations is to use Microsoft intermediate language (MSIL), either by compiling the class with Ilasm.exe (IL Assembler) or by emitting it in a dynamic assembly.

Un paramètre de type covariant est marqué avec le mot clé out (mot cléOut en Visual Basic, + pour l' assembleur MSIL).A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler). Vous pouvez utiliser un paramètre de type covariant comme valeur de retour d'une méthode qui appartient à une interface ou comme type de retour d'un délégué.You can use a covariant type parameter as the return value of a method that belongs to an interface, or as the return type of a delegate. Vous ne pouvez pas utiliser un paramètre de type covariant comme contrainte de type générique pour les méthodes d'interface.You cannot use a covariant type parameter as a generic type constraint for interface methods.

Notes

Si une méthode d'une interface a un paramètre qui est un type délégué générique, un paramètre de type covariant du type d'interface peut être utilisé pour spécifier un paramètre de type contravariant du type délégué.If a method of an interface has a parameter that is a generic delegate type, a covariant type parameter of the interface type can be used to specify a contravariant type parameter of the delegate type.

Un paramètre de type contravariant est marqué avec le mot clé in (mot cléIn en Visual Basic, - pour l' assembleur MSIL).A contravariant type parameter is marked with the in keyword (In keyword in Visual Basic, - for the MSIL Assembler). Vous pouvez utiliser un paramètre de type contravariant comme type d'un paramètre d'une méthode qui appartient à une interface ou comme type d'un paramètre d'un délégué.You can use a contravariant type parameter as the type of a parameter of a method that belongs to an interface, or as the type of a parameter of a delegate. Vous pouvez utiliser un paramètre de type contravariant comme contrainte de type générique pour une méthode d'interface.You can use a contravariant type parameter as a generic type constraint for an interface method.

Seuls les types d'interfaces et les types délégués peuvent avoir des paramètres de type variant.Only interface types and delegate types can have variant type parameters. Un type d'interface ou un type délégué peut avoir à la fois des paramètres de type covariant et contravariant.An interface or delegate type can have both covariant and contravariant type parameters.

Visual Basic et Visual C# ne vous permettent pas de violer les règles d'utilisation des paramètres de type covariant et contravariant ou d'ajouter des annotations de covariance et de contravariance aux paramètres qui diffèrent des types d'interfaces et des types délégués.Visual Basic and C# do not allow you to violate the rules for using covariant and contravariant type parameters, or to add covariance and contravariance annotations to the type parameters of types other than interfaces and delegates. L' assembleur MSIL n'exécute pas ce type de contrôle, mais une exception TypeLoadException est levée si vous essayez de charger un type qui viole les règles.The MSIL Assembler does not perform such checks, but a TypeLoadException is thrown if you try to load a type that violates the rules.

Pour obtenir des informations et un exemple de code, consultez Variance dans les interfaces génériques (C#) et Variance dans les interfaces génériques (Visual Basic).For information and example code, see Variance in Generic Interfaces (C#) and Variance in Generic Interfaces (Visual Basic).

Retour au débutBack to top

Liste des types d'interfaces et des types délégués génériques variantsList of Variant Generic Interface and Delegate Types

Dans .NET Framework 4, les types d’interfaces et les types délégués suivants ont des paramètres de type covariant et/ou contravariant.In the .NET Framework 4, the following interface and delegate types have covariant and/or contravariant type parameters.

TypeType Paramètres de type covariantCovariant type parameters Paramètres de type contravariantContravariant type parameters
Action<T> à Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>Action<T> to Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16> OuiYes
Comparison<T> OuiYes
Converter<TInput,TOutput> OuiYes OuiYes
Func<TResult> OuiYes
Func<T,TResult> à Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>Func<T,TResult> to Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult> OuiYes OuiYes
IComparable<T> OuiYes
Predicate<T> OuiYes
IComparer<T> OuiYes
IEnumerable<T> OuiYes
IEnumerator<T> OuiYes
IEqualityComparer<T> OuiYes
IGrouping<TKey,TElement> OuiYes
IOrderedEnumerable<TElement> OuiYes
IOrderedQueryable<T> OuiYes
IQueryable<T> OuiYes

Voir aussiSee also