Почему массивы C# ковариантны и какие преимущества это дает?

Мне трудно понять, почему массивы в C# являются ковариантными и какие преимущества может принести эта ковариантность. Рассмотрим следующий тривиальный пример кода:

object[] myArray = new string[1];
myArray[0] = 1;

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

Если я попытаюсь сделать то же самое с помощью дженериков, компилятор будет ворчать на меня, и я осознаю свою глупость на ранней стадии, поэтому мой вопрос таков: почему компилятор C# допускает эту ковариантность с массивами и, кроме того, каковы потенциальные преимущества?


person Matt B    schedule 18.08.2010    source источник


Ответы (3)


Эрик Липперт говорит:

К сожалению, этот особый вид ковариации нарушается. Он был добавлен в CLR, потому что этого требует Java, а разработчики CLR хотели иметь возможность поддерживать Java-подобные языки. Затем мы добавили его в C#, потому что он был в CLR. Это решение было довольно спорным в то время, и я не очень этому рад, но сейчас мы ничего не можем с этим поделать.

person mqp    schedule 18.08.2010

У Эрика Липперта есть статья об этом (на самом деле длинная серия о «дисперсии», я думаю, 11 частей)

http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx

И еще немного интересного

http://blogs.msdn.com/b/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx

person CaffGeek    schedule 18.08.2010
comment
mquander выигрывает за то, что цитирует блог, а не просто ссылается на него. - person Jon B; 19.08.2010
comment
@Jon B - и за цитирование соответствующего бита. - person Oded; 19.08.2010

Есть много ситуаций, в которых код будет перемещать или копировать элементы между слотами массива. При условии, что Arr является одномерным массивом, состоящим как минимум из двух элементов, следующий код будет работать независимо от типа Arr или содержащихся в нем элементов.

Object temp = Arr[1];
Arr[1] = Arr[0];
Arr[0] = temp;

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

Обратите внимание, что создание ковариантных массивов — это один из способов, позволяющих таким вещам, как методы сортировки, работать с произвольными типами массивов, но не единственный. Другим подходом было бы включение в System.Array нескольких методов и свойств, параметры которых не имеют никакого отношения к базовому типу элемента. Например, он может включать некоторые простые методы, такие как Swap, CopyItem и Roll, и, возможно, методы для выполнения более сложных перестановок с учетом списка индексов. Обратите внимание, что в отличие от кода, показанного выше, тип, подобный Int[], может переопределить свой метод Swap таким образом, чтобы избежать упаковки и распаковки.

person supercat    schedule 15.07.2013