Подтвердить что ты не робот

С#: Разница (ковариация/контравариантность) другое слово для полиморфизма?

Я пытаюсь выяснить точное значение слов Covariance и Contravariance из нескольких статей в Интернете и вопросов по StackOverflow, и из того, что я могу понять, это только другое слово для полиморфизма.

Правильно ли я с приведенным выше утверждением? Или я ошибаюсь?

4b9b3361

Ответ 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

Я думаю, что это особый вид полиморфизма, а не другое слово для него. Это полиморфизм в делегатах, где делегат с возвращаемым типом базы может принимать дочерний тип.