Может ли кто-нибудь дать мне простые примеры на C # конвариантности, контравариантности, инвариантности и контравариантности (если такая вещь существует).
Понятия не имею, что означает «противоинвариантность».В остальном все просто.
Вот пример ковариации:
void FeedTheAnimals(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals)
animal.Feed();
}
...
List<Giraffe> giraffes = ...;
FeedTheAnimals(giraffes);
Интерфейс IEnumerable<T>
равен ковариант .Тот факт, что Жираф конвертируется в Animal, подразумевает, что IEnumerable<Giraffe>
конвертируется в IEnumerable<Animal>
.Поскольку List<Giraffe>
реализует IEnumerable<Giraffe>
, этот код успешно выполняется в C # 4;в C # 3 это не удалось бы, потому что ковариация на IEnumerable<T>
не работала в C # 3.
Это должно иметь смысл.Последовательность жирафов можно рассматривать как последовательность животных.
Вот пример контравариантности:
void DoSomethingToAFrog(Action<Frog> action, Frog frog)
{
action(frog);
}
...
Action<Animal> feed = animal=>{animal.Feed();}
DoSomethingToAFrog(feed, new Frog());
Делегат Action<T>
является контравариантным.Тот факт, что Frog конвертируется в Animal, подразумевает, что Action<Animal>
конвертируется в Action<Frog>
.Обратите внимание, что это отношение является противоположным направлением ковариантного;вот почему это "против" вариант.Из-за конвертируемости этот код успешно выполняется;это не помогло бы в C # 3.
Это должно иметь смысл.Действие может принять любое животное;нам нужно действие, которое может принять любую Лягушку, и действие, которое может принять любое Животное, безусловно, может также взять любую Лягушку.
Пример неизменности:
void ReadAndWrite(IList<Mammal> mammals)
{
Mammal mammal = mammals[0];
mammals[0] = new Tiger();
}
Можем ли мы передать IList<Giraffe>
к этой вещи?Нет, потому что кто-то собирается вписать в него Тигра, а Тигра не может быть в списке Жирафов.Можем ли мы передать IList<Animal>
в эту вещь?Нет, потому что мы собираемся прочитать Млекопитающее из него, и список Животных мог бы содержать Лягушку.IList<T>
является инвариантом .Он может использоваться только в том виде, в каком он есть на самом деле.
Дополнительные сведения о дизайне этой функции см. В моей серии статей о том, как мы ее спроектировали и создали.
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/