С#:Является ли дисперсия (ковариация/контравариантность) другим словом для обозначения полиморфизма?
-
21-08-2019 - |
Вопрос
Я пытаюсь выяснить точное значение слов. Covariance
и Contravariance
из нескольких статей в Интернете и вопросов о StackOverflow, и, насколько я понимаю, это всего лишь другое слово для полиморфизма.
Прав ли я в приведенном выше утверждении?Или я ошибся?
Решение
Это определенно связано с полиморфизмом.Я бы не сказал, что это просто «еще одно слово» для обозначения полиморфизма — они относятся к очень специфическим ситуациям, когда вы можете относиться к одному типу, как если бы это был другой тип. в определенном контексте.
Например, с помощью нормального полиморфизма вы можете обрабатывать любую ссылку на Banana
как ссылка на Fruit
- но это не значит, что вы можете заменить Fruit
каждый раз ты видишь тип Banana
.Например, List<Banana>
нельзя рассматривать как List<Fruit>
потому что list.Add(new Apple())
действителен для List<Fruit>
но не для List<Banana>
.
Ковариация позволяет заменить «более крупный» (менее конкретный) тип в API, где исходный тип только используется в «выходном» положении (например,в качестве возвращаемого значения).Контравариантность позволяет заменить «меньший» (более конкретный) тип в API, где исходный тип только используется во «входном» положении.
Трудно описать все детали в одном сообщении SO (хотя, надеюсь, кто-то другой справится с этой задачей лучше, чем этот!).Эрик Липперт имеет отличный серия постов в блоге об этом.
Другие советы
Спасибо за все отклики, ребята.
Ответы Джона и Расмуса хороши, я бы просто добавил небольшое техническое примечание.
Да, говоря случайно и неформально, люди используют термины «ковариация» и «контравариантность» для обозначения определенного вида полиморфизма.То есть это своего рода полиморфизм, при котором вы относитесь к последовательности пауков так, как если бы это была последовательность животных.
Если бы мы овладели всей информатикой и попытались дать больше технических определений, я бы, вероятно, не сказал, что ковариантность и контравариантность являются «разновидностью полиморфизма».Я бы подошел к более техническому определению следующим образом:
Во-первых, я хотел бы отметить, что в C# есть два возможных типа полиморфизма, о которых вы, возможно, говорите, и важно их не путать.
Первый тип традиционно называется «специальным полиморфизмом», и это полиморфизм, при котором у вас есть метод M(Animal x), и вы передаете ему пауков, жирафов и валлаби, и метод одинаково обрабатывает переданные аргументы. способом, используя общность, гарантированную базовым классом Animal.
Второй вид традиционно называют «параметрическим полиморфизмом» или «генерическим полиморфизмом».Это возможность создать универсальный метод M<T>(T t)
а затем иметь в методе кучу кода, который снова обрабатывает аргумент единообразно на основе общности, гарантированной ограничениями на T.
Я думаю, вы говорите о первом виде полиморфизма.Но я хочу сказать, что мы можем определить полиморфизм как способность языка программирования относиться к разным вещам единообразно, основываясь на известной общности. (Например, известный базовый тип или известный реализованный интерфейс.)
Ковариантность и контравариантность – это способность языка программирования использовать преимущества общности между универсальными типами, выведенные из известных общностей их аргументов типа.
Вы можете думать о ко- и контравариантности как о продвинутой форме полиморфизма.Вы не только можете использовать дочерний класс, как если бы он был его родительским классом, с ко- и контравариантностью, полиморфизм распространяется на классы, относящиеся к полиморфным классам.
Представьте себе два класса:
public class Pet { /*...*/ }
public class Cat:Pet { /*...*/ }
Полиморфизм – это возможность использовать Cat
как Pet
:
void Feed(Pet pet) { /* ... */ }
Cat cat = ...
Feed(cat);
Ко- и контравариантность используются, чтобы говорить о возможности использования 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();
Эрик Липперт написал об этом отличную серию блогов, когда они впервые разрабатывали эту функцию.Часть первая здесь.
Я нашел эту коллекцию:
Ковариация и контравариантность в C#, часть первая
Ковариация и контравариация в C#, часть вторая:Ковариация массива
Ковариация и контравариантность в C#, часть третья:Отклонение конверсии группы участников
Ковариация и контравариация в C#, часть четвертая:Реальная дисперсия делегатов
Ковариация и контравариантность в C#, часть пятая:Функции высшего порядка повредили мой мозг
Ковариация и контравариация в C#, часть шестая:Вариант интерфейса
Ковариация и контравариация в C#, часть седьмая:Зачем нам вообще нужен синтаксис?
Ковариация и контравариация в C#, часть восьмая:Параметры синтаксиса
Ковариация и контравариация в C#, часть девятая:Критические изменения
Ковариация и контравариация в C#, часть десятая:Как справиться с двусмысленностью
Ковариантность и контравариантность, часть одиннадцатая:До бесконечности, но не дальше
Я думаю, что это особый вид полиморфизма, а не другое слово.Это полиморфизм в делегаты где делегат с базовым типом возврата может принимать дочерний тип.