Вопрос в том, "в чем разница между ковариацией и контравариантностью?"
Ковариация и контравариантность - это свойства функции отображения, которая связывает один элемент набора с другим . Более конкретно, отображение может быть ковариантным или контравариантным относительно отношения в этом наборе.
Рассмотрим следующие два подмножества множества всех типов C #. Во-первых:
{ Animal,
Tiger,
Fruit,
Banana }.
И, во-вторых, это явно связанный набор:
{ IEnumerable<Animal>,
IEnumerable<Tiger>,
IEnumerable<Fruit>,
IEnumerable<Banana> }
Существует операция сопоставления *1015* из первого набора во второй набор. То есть для каждого T в первом наборе соответствующий тип во втором наборе равен IEnumerable<T>
. Или, в кратком изложении, отображение T → IE<T>
. Обратите внимание, что это «тонкая стрела».
Со мной так далеко?
Теперь давайте рассмотрим отношение . Существует отношение совместимости присвоений между парами типов в первом наборе. Значение типа Tiger
может быть присвоено переменной типа Animal
, поэтому эти типы называются «совместимыми по назначению». Давайте напишем «значение типа X
может быть присвоено переменной типа Y
» в более короткой форме: X ⇒ Y
. Обратите внимание, что это «жирная стрела».
Итак, в нашем первом подмножестве приведены все отношения совместимости назначений:
Tiger ⇒ Tiger
Tiger ⇒ Animal
Animal ⇒ Animal
Banana ⇒ Banana
Banana ⇒ Fruit
Fruit ⇒ Fruit
В C # 4, который поддерживает ковариантную совместимость присваивания определенных интерфейсов, существует отношение совместимости присвоения между парами типов во втором наборе:
IE<Tiger> ⇒ IE<Tiger>
IE<Tiger> ⇒ IE<Animal>
IE<Animal> ⇒ IE<Animal>
IE<Banana> ⇒ IE<Banana>
IE<Banana> ⇒ IE<Fruit>
IE<Fruit> ⇒ IE<Fruit>
Обратите внимание, что отображение T → IE<T>
сохраняет существование и направление совместимости присвоения . То есть, если X ⇒ Y
, то также верно, что IE<X> ⇒ IE<Y>
.
Если у нас есть две вещи по обе стороны от жирной стрелки, то мы можем заменить обе стороны чем-то с правой стороны соответствующей тонкой стрелки.
Отображение, которое обладает этим свойством по отношению к определенному отношению, называется «ковариантным отображением». Это должно иметь смысл: последовательность Тигров может использоваться там, где необходима последовательность Животных, но обратное неверно. Последовательность животных не обязательно может быть использована там, где нужна последовательность тигров.
Это ковариация. Теперь рассмотрим это подмножество множества всех типов:
{ IComparable<Tiger>,
IComparable<Animal>,
IComparable<Fruit>,
IComparable<Banana> }
теперь у нас есть отображение из первого набора в третий набор T → IC<T>
.
В C # 4:
IC<Tiger> ⇒ IC<Tiger>
IC<Animal> ⇒ IC<Tiger> Backwards!
IC<Animal> ⇒ IC<Animal>
IC<Banana> ⇒ IC<Banana>
IC<Fruit> ⇒ IC<Banana> Backwards!
IC<Fruit> ⇒ IC<Fruit>
То есть отображение T → IC<T>
имеет , сохранившее существование, но полностью изменившее направление совместимости назначений. То есть если X ⇒ Y
, то IC<X> ⇐ IC<Y>
.
Отображение, которое сохраняет, но обращает отношение, называется контравариантным отображением.
Опять же, это должно быть четко правильно. Устройство, которое может сравнивать двух животных, также может сравнивать двух тигров, но устройство, которое может сравнивать двух тигров, не обязательно может сравнивать любые два животных.
Так что в C # 4 разница между ковариацией и контравариантностью. Ковариантность сохраняет направление присваиваемости. Контравариантность реверс ит.