Partager via


Utilisation de la variance dans les interfaces pour les collections génériques (C#)

Une interface covariante permet à ses méthodes de retourner plus de types dérivés que ceux spécifiés dans l’interface. Une interface contravariante permet à ses méthodes d’accepter des paramètres de types moins dérivés que ceux spécifiés dans l’interface.

Dans .NET Framework 4, plusieurs interfaces existantes sont devenues covariantes et contravariantes. Ceux-ci incluent IEnumerable<T> et IComparable<T>. Cela vous permet de réutiliser des méthodes qui fonctionnent avec des collections génériques de types de base pour les collections de types dérivés.

Pour obtenir la liste des interfaces variant dans .NET, consultez Variance dans les interfaces génériques (C#) .

Conversion de collections génériques

L’exemple suivant illustre les avantages de la prise en charge de la covariance dans l’interface IEnumerable<T> . La PrintFullName méthode accepte une collection du IEnumerable<Person> type en tant que paramètre. Toutefois, vous pouvez la réutiliser pour une collection du IEnumerable<Employee> type, car Employee hérite Person.

// Simple hierarchy of classes.  
public class Person  
{  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
}  
  
public class Employee : Person { }  
  
class Program  
{  
    // The method has a parameter of the IEnumerable<Person> type.  
    public static void PrintFullName(IEnumerable<Person> persons)  
    {  
        foreach (Person person in persons)  
        {  
            Console.WriteLine("Name: {0} {1}",  
            person.FirstName, person.LastName);  
        }  
    }  
  
    public static void Test()  
    {  
        IEnumerable<Employee> employees = new List<Employee>();  
  
        // You can pass IEnumerable<Employee>,
        // although the method expects IEnumerable<Person>.  
  
        PrintFullName(employees);  
  
    }  
}  

Comparaison des collections génériques

L'exemple suivant illustre les avantages du support de la contravariance dans l'interface IEqualityComparer<T>. La classe PersonComparer implémente l’interface IEqualityComparer<Person>. Toutefois, vous pouvez réutiliser cette classe pour comparer une séquence d’objets du Employee type, car Employee hérite Person.

// Simple hierarchy of classes.  
public class Person  
{  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
}  
  
public class Employee : Person { }  
  
// The custom comparer for the Person type  
// with standard implementations of Equals()  
// and GetHashCode() methods.  
class PersonComparer : IEqualityComparer<Person>  
{  
    public bool Equals(Person x, Person y)  
    {
        if (Object.ReferenceEquals(x, y)) return true;  
        if (Object.ReferenceEquals(x, null) ||  
            Object.ReferenceEquals(y, null))  
            return false;
        return x.FirstName == y.FirstName && x.LastName == y.LastName;  
    }  
    public int GetHashCode(Person person)  
    {  
        if (Object.ReferenceEquals(person, null)) return 0;  
        int hashFirstName = person.FirstName == null  
            ? 0 : person.FirstName.GetHashCode();  
        int hashLastName = person.LastName.GetHashCode();  
        return hashFirstName ^ hashLastName;  
    }  
}  
  
class Program  
{  
  
    public static void Test()  
    {  
        List<Employee> employees = new List<Employee> {  
               new Employee() {FirstName = "Michael", LastName = "Alexander"},  
               new Employee() {FirstName = "Jeff", LastName = "Price"}  
            };  
  
        // You can pass PersonComparer,
        // which implements IEqualityComparer<Person>,  
        // although the method expects IEqualityComparer<Employee>.  
  
        IEnumerable<Employee> noduplicates =  
            employees.Distinct<Employee>(new PersonComparer());  
  
        foreach (var employee in noduplicates)  
            Console.WriteLine(employee.FirstName + " " + employee.LastName);  
    }  
}  

Voir aussi