Теперь, на мой неопытный взгляд, ковариация кажется такой же, как приведение вверх, за исключением того, что она относится к приведению коллекций. (И аналогичное утверждение можно сделать относительно контравариантности и принижения).
Это действительно так просто?
Ковариация не связана с повышением класса, хотя я понимаю, почему вы думаете, что это связано.
Ковариация связана со следующей очень простой идеей. Допустим, у вас есть переменная derivedSequence
типа IEnumerable<Derived>
. Допустим, у вас есть переменная baseSequence
типа IEnumerable<Base>
. Здесь Derived
происходит от Base
. Затем, с ковариацией, следующее является допустимым присвоением, и происходит неявное преобразование ссылки:
baseSequence = derivedSequence;
Обратите внимание, что это не повышение. Это не тот случай, когда IEnumerable<Derived>
происходит от IEnumerable<Base>
. Скорее, именно ковариация позволяет присвоить значение переменной derivedSequence
переменной baseSequence
. Идея состоит в том, что переменным типа Base
можно присваивать объекты типа Derived
, а поскольку IEnumerable<T>
является ковариантным в своем параметре, объекты типа IEnumerable<Derived>
можно присваивать переменным типа IEnumerable<Base>
.
Конечно, я еще толком не объяснил, что такое ковариация. В общем, ковариация связана со следующей простой идеей. Допустим, у вас есть отображение F
из типов в типы (я буду обозначать это отображение F<T>
; для данного типа T
его изображением при отображении F
будет F<T>
.) Предположим, что это отображение обладает следующим особым свойством:
если X
является назначением, совместимым с Y
, то F<X>
также является назначением, совместимым с F<Y>
.
В этом случае мы говорим, что F
является ковариантным по своему параметру T
. (Здесь сказать, что A
является присваиванием, совместимым с B
, где A
и B
являются ссылочными типами, означает, что экземпляры B
могут храниться в переменных типа A
.)
В нашем случае IEnumerable<T>
в C# 4.0 — неявное преобразование ссылок из экземпляров IEnumerable<Derived>
в IEnumerable<Base>
, если Derived
является производным от Base
. Направление совместимости присваивания сохраняется, и поэтому мы говорим, что IEnumerable<T>
является ковариантным в своем параметре типа.
person
jason
schedule
15.07.2011