Самый простой способ понять, почему это запрещено, - это следующий пример:
abstract class Fruit
{
}
class Apple : Fruit
{
}
class Banana : Fruit
{
}
// This should intuitively compile right? Cause an Apple is Fruit.
List<Fruit> fruits = new List<Apple>();
// But what if I do this? Adding a Banana to a list of Apples
fruits.Add(new Banana());
Последнее утверждение разрушило бы безопасность типов .NET.
Однако массивы позволяют это:
Fruit[] fruits = new Apple[10]; // This is perfectly fine
Однако включение Banana
в fruits
все равно нарушит безопасность типов, поэтому .NET должен выполнять проверку типа при каждой вставке массива и генерировать исключение, если на самом деле это не Apple
. Это потенциально (небольшое) снижение производительности, но это можно обойти, создав struct
оболочку для любого типа, поскольку эта проверка не выполняется для типов значений (потому что они не могут наследовать ни от чего). Сначала я не понимал, почему было принято это решение, но вы довольно часто будете сталкиваться с тем, почему это может быть полезно. Чаще всего используется String.Format
, который принимает params object[]
, и в него можно передать любой массив.
Однако в .NET 4 существует безопасная ковариация / контравариантность типов, которая позволяет выполнять некоторые подобные присваивания, но только в том случае, если они доказуемо безопасны. Что доказуемо безопасно?
IEnumerable<Fruit> fruits = new List<Apple>();
Вышеупомянутое работает в .NET 4, потому что IEnumerable<T>
стало IEnumerable<out T>
. out
означает, что T
может выходить только вне из fruits
и что на IEnumerable<out T>
нет никакого метода, который бы когда-либо принимал T
в качестве параметра, поэтому вы никогда не сможете неправильно передать Banana
в IEnumerable<Fruit>
.
Контравариантность во многом такая же, но я всегда забываю ее точные детали. Неудивительно, что для этого теперь есть ключевое слово in
для параметров типа.
person
JulianR
schedule
11.01.2011
IEnumerable<AbstractPackageCall>
вместоList<AbstractPackageCall>
, тогда это будет работать, посколькуIEnumerable<>
поддерживает ковариацию. - person Russ Cam   schedule 11.01.2011