Разница между ковариацией и upcasting
в чем разница между ковариацией и upcasting, или, точнее, почему они дали разные имена?
Я видел следующий пример, называемый "upcasting":
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 ответов:
это действительно так просто?
ковариация не связана с повышением, хотя я понимаю, почему вы думаете, что это связано.
ковариация - это следующая очень простая идея. Допустим, у вас есть переменная
derivedSequenceтипаIEnumerable<Derived>. Допустим, у вас есть переменнаяbaseSequenceтипаIEnumerable<Base>. Вот,Derivedпроисходит отBase. Затем, с ковариацией, следующее является юридическим назначением, и происходит неявное преобразование ссылки:baseSequence = derivedSequence;обратите внимание, что это не upcasting. Это не тот случай, что
F от типов к типам (я обозначу это сопоставлениеIEnumerable<Derived>происходит отIEnumerable<Base>. Скорее, это ковариация, которая позволяет присвоить значение переменнойderivedSequenceпеременнойbaseSequence. Идея заключается в том, что переменные типаBaseможет быть назначается из объектов типаDerived, и сIEnumerable<T>является ковариантным по своему параметру, объекты типаIEnumerable<Derived>может быть присвоено переменным типаIEnumerable<Base>.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>является ковариантным по своему параметру типа.
литье относится к изменению статического типа объекты и выражений.
дисперсия относится к взаимозаменимость или эквивалентность типов в некоторых ситуациях (например, параметры, универсальные и возвращаемые типы).
IEnumerable<string>не является производным отIEnumerable<object>, Так что бросок между ними не является upcasting. IEnumerable является ковариантным по своему параметру типа и строке - это производный от объекта, поэтому приведение разрешено.
почему они разных понятий, что, в отличие от upcasting, ковариация не всегда разрешено. Проектировщикам системы типов было бы легко сделать
IList<Cat>считается "производные" СIList<Animal>, но потом мы столкнулись с проблемами:IList<Cat> cats = new List<Cat>(); IList<Animal> animals = cats; animals.Add(new Dog()); //Uh oh!если бы это было разрешено, теперь наш!--4--> список будет содержать
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
сообщение в блоге ниже имеет хорошее объяснение этого:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
из того, что я могу собрать, ковариация устраняет необходимость в явном понижении после предыдущего повышения. Как правило, если вы повышаете объект, вы можете получить доступ только к методам и атрибутам базового типа, с ковариацией, похоже, вы можете подразумевать понижение, заменяя меньшие производные типы более производными типами в объявлении более производного класса.