C# 4.0 covariance et contravariance8 mars 2010

General Code

Une nouveauté technique a fait son apparition avec l’arrivée du Framework .NET 4.0 : la covariance et la contravariance.

Ils définissent la possibilité d’utiliser un type dérivé à l’endroit où est attendu un type parent.

Les classes génériques

Par exemple, si vous écrivez dans une version antérieure à la 4.0 ce qui suit :

class Customer
{
    public int CustomerId { get; set; }
}

class SpecialCustomer : Customer
{
    ...
}

...
static void PrintCustomers(IEnumerable<Customer> customers)
{

}
...

Vous ne pourrez pas appeler la méthode PrintCustomers avec le type IEnumerable<SpecialCustomer>.

Le Framework .NET 4.0 redéfinit les classes génériques de System.Collections.Generic sur ce modèle :

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

Ici, le mot-clé out applique la contravariance à l’interface IEnumerable<T>.

De ce fait, on pourra appeler PrintCustomers avec un paramètre du type List<SpecialCustomer> par exemple.

Les delegates

La covariance peut s’appliquer aux types delegate. Ce qui suit devient possible :

public delegate Customer CustomerChangedHandler();
...
// Méthode compatible avec le delegate CustomerChangedHandler
SpecialCustomer OnCustomerChanged() { ... }
...
CustomerChangedHandler handler = OnCustomerChanged;

Les tableaux

Les tableaux peuvent également s’utiliser de manière plus souple grâce à la contravariance. Ceci est valide en C# 4.0 :

void EnumerateCustomers(Customer[] customers) { ... }
...
EnumerateCustomers(new SpecialCustomer[2]);

Explication

Les deux termes (covariance et contravariance) sont similaires à ceci près que la covariance s’applique aux paramètres de sortie de fonction (retour) alors que la contravariance s’applique aux paramètres d’entrée.

Heureusement, il n’est pas nécessaire de connaître ces définitions pour pouvoir les utiliser :)

Un exemple avec cet article de la MSDN : Covariance et contravariance dans les délégués (C#)