Допустим, у вас есть класс Person и класс, который вытекает из него, Учитель. У вас есть некоторые операции, которые принимают аргумент IEnumerable
. В вашем классе School у вас есть метод, который возвращает IEnumerable
. Ковариация позволяет вам напрямую использовать этот результат для методов, которые принимают IEnumerable
, заменяя более производный тип для менее производного (более общего) типа. Контравариантность, контр-интуитивно, позволяет использовать более общий тип, где указан более производный тип. См. Также https://msdn.microsoft.com/en-us/library/dd799517.aspx
public class Person
{
public string Name { get; set; }
}
public class Teacher : Person { }
public class MailingList
{
public void Add(IEnumerable people) { ... }
}
public class School
{
public IEnumerable GetTeachers() { ... }
}
public class PersonNameComparer : IComparer
{
public int Compare(Person a, Person b)
{
if (a == null) return b == null ? 0 : -1;
return b == null ? 1 : Compare(a,b);
}
private int Compare(string a, string b)
{
if (a == null) return b == null ? 0 : -1;
return b == null ? 1 : a.CompareTo(b);
}
}
...
var teachers = school.GetTeachers();
var mailingList = new MailingList();
// Add() is covariant, we can use a more derived type
mailingList.Add(teachers);
// the Set constructor uses a contravariant interface, IComparer,
// we can use a more generic type than required. See https://msdn.microsoft.com/en-us/library/8ehhxeaf.aspx for declaration syntax
var teacherSet = new SortedSet(teachers, new PersonNameComparer());