Разница между ковариацией и апскейтингом - PullRequest
60 голосов
/ 15 июля 2011

В чем разница между ковариацией и апкастингом или, более конкретно, почему им даны разные имена?

Я видел следующий пример, называемый «апкастинг»:

string s = "hello";
object o = s;  //upcast to 'string' to 'object'

Принимая во внимание, что следующее, что я видел, называется «ковариация»:

string[] s = new string[100];
object[] o = s;

IEnumerable<string> ies = new List<string>();
IEnumerable<object> ieo = ies;

Теперь, на мой неподготовленный взгляд, ковариация, похоже, такая же, как и выкидывание, за исключением того, что оно относится к приему коллекций.(И аналогичное утверждение может быть сделано в отношении контравариантности и понижения).

Неужели это так просто?

Ответы [ 6 ]

57 голосов
/ 15 июля 2011

Теперь, на мой неопытный взгляд, ковариация, похоже, такая же, как и апскейтинг, за исключением того, что она относится к кастингу коллекций. (И аналогичное утверждение может быть сделано в отношении контравариантности и понижения).

Неужели это так просто?

Ковариантность не связана с апскейтингом, хотя я понимаю, почему вы думаете, что это связано.

Ковариантность о следующей очень простой идее. Допустим, у вас есть переменная derivedSequence типа IEnumerable<Derived>. Допустим, у вас есть переменная baseSequence типа IEnumerable<Base>. Здесь Derived происходит от Base. Затем, с ковариацией, следующее является законным назначением, и происходит неявное преобразование ссылки:

baseSequence = derivedSequence;

Обратите внимание, что это не upcasting. Это не тот случай, когда 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> ковариантен в параметре типа.

19 голосов
/ 15 июля 2011

Приведение относится к изменению статического типа объектов и выражений .

Дисперсия относится к взаимозаменяемости или эквивалентноститипы в определенных ситуациях (например, параметры, обобщенные и возвращаемые типы).

15 голосов
/ 15 июля 2011

IEnumerable<string> не является производным от IEnumerable<object>, поэтому приведение между ними не является апскейдингом. IEnumerable является ковариантным по своему параметру типа, а строка является производной от объекта, поэтому приведение разрешено.

7 голосов
/ 15 июля 2011

Причина, по которой они представляют разные концепции, заключается в том, что, в отличие от апскейтинга, ковариация не всегда допускается.Разработчикам системы типов было бы легко заставить IList<Cat> считаться «производным» от IList<Animal>, но тогда мы столкнулись с проблемами:

IList<Cat> cats = new List<Cat>();
IList<Animal> animals = cats; 
animals.Add(new Dog()); //Uh oh!

Если бы это было разрешено, теперь наш список cats будет содержать Dog!

В отличие от этого, интерфейс IEnumerable<T> не имеет возможности добавлять элементы, так что это совершенно правильно (в C # 4.0):

IList<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
//There's no way to add things to an IEnumerable<Animal>, so here we are ok
1 голос
/ 15 июля 2011

В этом блоге есть хорошее объяснение:

http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

0 голосов
/ 04 сентября 2014

Из того, что я могу собрать, ковариация устраняет необходимость явного снижения рейтинга после предыдущего повышения. Обычно, если вы выгружаете объект, вы можете получить доступ только к методам и атрибутам базового типа, с ковариацией кажется, что вы можете подразумевать понижение, заменяя меньшие производные типы более производными типами в объявлении более производного класса.

...