Как получается, что U [] можно преобразовать в T []? - PullRequest
6 голосов
/ 31 августа 2010

Очевидно, что тип массива T[] не является ковариантным , так как элементы T[] могут быть установлены с помощью индекса.

И, тем не менее, U[] может быть приведен к T[] без каких-либо жалоб со стороны компилятора, если U происходит от T.

Man[] men = new[] { new Man("Aaron"), new Man("Billy"), new Man("Charlie") };
Person[] people = (Person[])men;

В приведенном выше коде кажется, что men и people, похоже, содержат ссылку на один и тот же объект Array. Эффект установки men[0] = new Man("Aidan") можно увидеть на people[0]. Аналогичным образом, попытка people[0] = new Woman("Debbie") приводит к ArrayTypeMismatchException во время выполнения *.

Означает ли это, что тип T[] фактически выполняет проверку типов при каждом вызове set? Похоже, что это необходимо, если разрешено приводить массивы таким образом.

Полагаю, мой вопрос: Как это возможно? Мне ясно, что U[] не происходит от T[]. Для меня также неясно , могу ли я когда-нибудь определить свой собственный тип, который будет работать таким образом: на самом деле быть инвариантным, но действовать ковариантным.


* Хотя дисперсия массива, по-видимому, разрешена CLR , любой язык может запретить приведение между типами массивов. Тем не менее, похоже, что это поведение идентично в VB.NET:

Dim men = New Man() { New Man("Aaron"), New Man("Billy"), New Man("Charlie") }
Dim people = CType(men, Person())

Ответы [ 3 ]

7 голосов
/ 31 августа 2010

Это специальное поведение массивов и не может быть реплицировано ни в каком другом типе.

Обычно это считается ошибкой .

2 голосов
/ 31 августа 2010

Это работает только потому, что это особая функция, которая является частью CLR. Массивы автоматически ковариантны, хотя технически это не так. Компиляторы просто должны это знать и генерировать правильные проверки типов.

Несмотря на то, что некоторые считают эту функцию ошибкой, было очень важно иметь до создания типобезопасных коллекций и универсальной ковариации интерфейса. Вы даже не сможете написать функцию для сортировки массива без нее.

1 голос
/ 31 августа 2010

Эрик объяснил это очень четко здесь: http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx.

Краткое резюме: если D наследует B, то D [] ковариантно B [].Предположим, что D2 также наследуется от B, тогда

B[] b = new D[10]; 
b[0] = new D1();

выдает исключение.Да, это не хорошо, но это так.

...