Verwenden von Varianz in Schnittstellen für generische Auflistungen (C#)Using Variance in Interfaces for Generic Collections (C#)

Eine kovariante Schnittstelle ermöglicht den zugehörigen Methoden, mehr abgeleitete Typen zurückzugeben, als in der Schnittstelle angegeben sind.A covariant interface allows its methods to return more derived types than those specified in the interface. Eine kontravariante Schnittstelle ermöglicht den zugehörigen Methoden, Parameter von weniger abgeleiteten Typen anzunehmen, als in der Schnittstelle angegeben sind.A contravariant interface allows its methods to accept parameters of less derived types than those specified in the interface.

In .NET Framework 4 wurden mehrere vorhandene Schnittstellen kovariant und kontravariant.In .NET Framework 4, several existing interfaces became covariant and contravariant. Dazu gehören IEnumerable<T> und IComparable<T>.These include IEnumerable<T> and IComparable<T>. Dadurch können Sie Methoden wiederverwenden, die mit generischen Auflistungen von Basistypen für Sammlungen von abgeleiteten Typen verwendet werden.This enables you to reuse methods that operate with generic collections of base types for collections of derived types.

Eine Liste von varianten Schnittstellen in .NET Framework finden Sie unter Varianz in generischen Schnittstellen (C#).For a list of variant interfaces in the .NET Framework, see Variance in Generic Interfaces (C#).

Konvertieren von generischen AuflistungenConverting Generic Collections

Das folgende Beispiel veranschaulicht die Vorteile der Unterstützung von Kovarianz in der IEnumerable<T>-Schnittstelle.The following example illustrates the benefits of covariance support in the IEnumerable<T> interface. Die PrintFullName-Methode akzeptiert eine Auflistung vom Typ IEnumerable<Person> als Parameter.The PrintFullName method accepts a collection of the IEnumerable<Person> type as a parameter. Sie können dies jedoch für eine Auflistung des Typs IEnumerable<Employee> wiederverwenden, da Employee Person erbt.However, you can reuse it for a collection of the IEnumerable<Employee> type because Employee inherits 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);  

    }  
}  

Vergleichen von generischen AuflistungenComparing Generic Collections

Das folgende Beispiel veranschaulicht die Vorteile der Unterstützung von Kontravarianz in der IComparer<T>-Schnittstelle.The following example illustrates the benefits of contravariance support in the IComparer<T> interface. Die PersonComparer-Klasse implementiert die IComparer<Person>-Schnittstelle.The PersonComparer class implements the IComparer<Person> interface. Sie können diese Klasse jedoch zum Vergleich einer Sequenz von Objekten des Typs Employee wiederverwenden, da Employee Person erbt.However, you can reuse this class to compare a sequence of objects of the Employee type because Employee inherits 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);  
    }  
}  

Siehe auchSee Also

Varianz in generischen SchnittstellenVariance in Generic Interfaces (C#)