С#: Разница (ковариация/контравариантность) другое слово для полиморфизма?
Я пытаюсь выяснить точное значение слов Covariance
и Contravariance
из нескольких статей в Интернете и вопросов по StackOverflow, и из того, что я могу понять, это только другое слово для полиморфизма.
Правильно ли я с приведенным выше утверждением? Или я ошибаюсь?
Ответы
Ответ 1
Это, безусловно, связано с полиморфизмом. Я бы не сказал, что они просто "другое слово" для полиморфизма, хотя они - очень специфические ситуации, где вы можете рассматривать один тип, как если бы это был другой тип в определенном контексте.
Например, при нормальном полиморфизме вы можете рассматривать любую ссылку на Banana
как ссылку на Fruit
- но это не значит, что вы можете подставлять Fruit
каждый раз, когда вы видите тип Banana
. Например, a List<Banana>
нельзя рассматривать как List<Fruit>
, потому что list.Add(new Apple())
действителен для List<Fruit>
, но не для List<Banana>
.
Covariance позволяет заменить "более крупный" (менее конкретный) тип в API, где исходный тип используется только в "выходной" позиции (например, в качестве возвращаемого значения). Контравариантность позволяет заменить "меньший" (более конкретный) тип в API, где исходный тип используется только в позиции "ввода".
Трудно разобраться во всех деталях в одном сообщении SO (хотя, надеюсь, кто-то другой сделает лучше, чем это!). Эрик Липперт имеет отличную об этом.
Ответ 2
Спасибо за все крики, ребята.
Ответы Джона и Расмуса прекрасны, я бы просто добавил техническую заметку.
Говоря небрежно и неформально, да, люди используют "ковариацию" и "контравариантность" для обозначения определенного вида полиморфизма. То есть, тип полиморфизма, где вы относитесь к последовательности пауков, как если бы это была последовательность животных.
Если бы мы получили все компьютерные знания и попытались сделать больше технических определений, я бы, вероятно, не сказал бы, что ковариация и контравариантность являются "своего рода полиморфизмом". Я бы подошел к более техническому определению:
Во-первых, я хотел бы отметить, что в С# существуют два возможных типа полиморфизма, о которых вы могли бы говорить, и важно не путать их.
Первый вид традиционно называется "ad hoc polymorphism" и что полиморфизм, в котором у вас есть метод M (Animal x), и вы передаете ему пауки и жирафы и валлаби, а метод равномерно обрабатывает его пройденный аргументы аналогичным образом, используя общие черты, гарантированные базовым классом Animal.
Второй вид традиционно называют "параметрическим полиморфизмом" или "родовым полиморфизмом". То, что возможность сделать общий метод M<T>(T t)
, а затем снова содержит кучу кода в методе, рассматривает аргумент равномерно на основе общности, гарантируемой ограничениями на T.
Я думаю, вы говорите о первом типе полиморфизма. Но я считаю, что мы можем определить полиморфизм как способность языка программирования относиться к разным вещам равномерно на основе известной общности. (Например, известный базовый тип или известный реализованный интерфейс.)
Ковариация и контравариантность - это способность языка программирования использовать общие черты между родовыми типами, выведенными из известных общности их аргументов типа.
Ответ 3
Вы можете думать о совместной и контравариантности как о передовой форме полиморфизма. Мало того, что вы можете использовать дочерний класс, как если бы он был его родительским классом, с ко- и контравариантностью, полиморфизм распространяется на классы, относящиеся к полиморфным классам.
Представьте себе два класса:
public class Pet { /*...*/ }
public class Cat:Pet { /*...*/ }
Полиморфизм может использовать a Cat
как a Pet
:
void Feed(Pet pet) { /* ... */ }
Cat cat = ...
Feed(cat);
Co- и контравариантность используется, чтобы говорить о возможности использовать ICollection<Cat>
как ICollection<Pet>
(ковариация):
void FeedAll(ICollection<Pet> pets) { /* ... */ }
List<Cat> cats = ...
FeedAll(cats);
или использовать Action<Pet>
как Action<Cat>
(контравариантность):
Action<Pet> GetFeeder() { /* ... */ }
Action<Cat> feeder = GetFeeder();
Эрик Липперт написал замечательную серию блога об этом, когда они впервые разрабатывали эту функцию. Часть первая здесь.
Ответ 4
Я нашел эту коллекцию:
Ковариация и контравариантность в С#, часть первая
Ковариация и контравариантность в С#, часть вторая: Ковариация массивов
Ковариация и контравариантность в С#, часть третья: вариация вариаций членов группы
Ковариация и контравариантность в С#, часть четвертая: отклонение в реальном деле
Ковариация и контравариантность в С#, часть пятая: функции более высокого порядка Hurt My Brain
Ковариация и контравариантность в С#, часть 6: Отклонение интерфейса
Ковариация и контравариантность в С# Часть седьмая: зачем нам нужен синтаксис?
Ковариация и контравариантность в С#, часть восьмая: параметры синтаксиса
Ковариация и контравариантность в С#, часть девять: нарушение изменений
Ковариация и контравариантность в С#, часть десятая: Работа с неоднозначностью
Ковариация и контравариантность, часть одиннадцатая: до бесконечности, но не выше
Ответ 5
Я думаю, что это особый вид полиморфизма, а не другое слово для него. Это полиморфизм в делегатах, где делегат с возвращаемым типом базы может принимать дочерний тип.