2010-08-31 2 views
6

Понятно, что тип массива T[] не равен covariant, так как элементы T[] могут быть установлены по индексу.Каким образом U [] можно использовать для 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[]. Это также неясно мне мог ли я когда-либо определить свой собственный тип, который работал бы таким образом: на самом деле be инвариант, но act covariant.


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

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

можете ли вы пометить это конкретным языком для тех из нас, кто не знает, с кем вы разговариваете? –

+0

@Philip: I * could *, но он, по-видимому, применим и к VB.NET и C#. Вот почему я пошел с тегом .net. –

+0

Язык не может полностью запретить его - метод, написанный на языке X, может получить ковариационный массив из языка Y. – SLaks

ответ

7

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

It is generally regarded as a mistake.

+1

Итак, как это работает с массивами? –

+1

@ Dan: Специальная магия в CLR. Да; каждый набор массивов (непечатаемого типа) выполняет проверку типа. – SLaks

+0

@ Дань Тао вы посмотрели связанный пост? Это объясняется там – jeroenh

2

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

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

+0

Компиляторам не нужно знать это, кроме правил кастинга. Это выполняется во время выполнения. – SLaks

1

Эрик объяснил это очень четко здесь: 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(); 

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

Смежные вопросы