Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Ковариантный интерфейс позволяет своим методам возвращать более производные типы, чем указанные в интерфейсе. Контравариантный интерфейс позволяет своим методам принимать параметры менее производных типов, чем указанные в интерфейсе.
В .NET Framework 4 несколько существующих интерфейсов стали ковариантными и контравариантными. В их числе IEnumerable<T> и IComparable<T>. Это позволяет повторно использовать методы, работающие с универсальными коллекциями базовых типов для коллекций производных типов.
Список вариантов интерфейсов в .NET см. в разделе "Вариативность" в универсальных интерфейсах (C#).
Преобразование универсальных коллекций
В следующем примере показаны преимущества поддержки ковариации в интерфейсе IEnumerable<T> . Метод PrintFullName принимает коллекцию IEnumerable<Person> типа в качестве параметра. Однако его можно повторно использовать для коллекции IEnumerable<Employee> типа, так как Employee наследуется 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);
}
}
Сравнение универсальных коллекций
В следующем примере показаны преимущества поддержки контравариантности в интерфейсе IEqualityComparer<T> . Класс PersonComparer реализует интерфейс IEqualityComparer<Person>. Однако этот класс можно повторно использовать для сравнения последовательности объектов Employee типа, так как Employee наследуется 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);
}
}