Почему массивная дисперсия считается настолько ужасной?
В .NET ссылочные типы массивов являются ко-вариантами. Это считается ошибкой. Однако я не понимаю, почему это так плохо, учитывая следующий код:
string[] strings = new []{"Hey there"};
object[] objects = strings;
objects[0] = new object();
Ох, это компилируется и будет терпеть неудачу во время выполнения. Поскольку мы пытались вставить объект в строку []. Хорошо, я согласен, что воняет, но T [] расширяет массив и также реализует IList
(и IList<T>
, интересно, реализует ли он IList<BaseType>
... > . И Array, и IList позволяют нам сделать тот же ужас ошибка.
string[] strings = new []{"Hey there"};
Array objects = strings;
objects.SetValue(new object(),new[]{0});
Версия IList
string[] strings = new []{"Hey there"};
IList objects = strings;
objects[0] = new object();
Классы T [] генерируются CLR и должны включать проверку типа на эквивалент метода set_Item
(в массивах на самом деле нет).
Является ли проблема, связанная с тем, что установка T [] должна выполнять проверку типа во время выполнения (что нарушает безопасность типа, которую вы ожидаете во время компиляции)? Почему считается, что массивы могут проявлять это свойство, когда есть эквивалентные средства для стрельбы в ногу через предоставленные средства выше?
Ответы
Ответ 1
Да, IList
и Array
позволяют совершить ту же ошибку - потому что для них используются слабо типизированные API.
Массивы выглядят так, как будто они строго типизированы (во время компиляции), но на самом деле это не так. Они могли так легко быть безопасными (и быстрее), но это не так. Это просто потерянная возможность как для производительности, так и для безопасности во время компиляции: (
Ответ 2
В .NET ссылочные типы массивов являются ко-вариантами. Это считается ошибкой.
Ковариация с разбивкой по типам безопасности рассматривается некоторыми людьми как ошибка в дизайне .NET. Это не так считают все люди. Я не считаю это ошибкой; Я считаю это неудачным выбором. Все процессы проектирования включают выбор между нежелательными альтернативами. В этом случае выбор заключался в добавлении небезопасного неявного преобразования, которое накладывает затраты времени выполнения на все записи массива или на создание системы типов, которая не может легко реализовать систему типов Java. То, что жесткий выбор и дизайнеры системы типов сделали лучший выбор, они могли с информацией, которую они имели.
Это объяснение, конечно, просто вопрос попрошайничества; разве это не просто случай, когда разработчики Java допустили ошибку? Возможно, да, возможно нет; вероятно, разработчики Java также столкнулись с компромиссами в дизайне своей системы типов. Любые эксперты по истории разработки системы типа Java, которые хотели бы прослушивать здесь, на что эти компромиссы, мне было бы интересно узнать.
I, с десятилетней ретроспективностью, лично предпочел бы, если бы дизайнеры системы типа .NET решили избежать ковариации в области безопасности. Но это не делает этот выбор "ошибкой", это просто делает его несколько неудачным.
Является ли проблема, связанная с тем, что установка T [] должна выполнять проверку типа во время выполнения (что нарушает безопасность типа, которую вы ожидаете во время компиляции)?
Да. Это означает, что код, который выглядит так, как он должен всегда выполняться успешно, может выйти из строя во время выполнения. И это означает, что правильный код имеет наказание за выполнение.
Почему это считается вредным для массивов, чтобы проявить это свойство, когда есть эквивалентные средства, чтобы стрелять в ногу через предоставленные средства выше?
Это странный вопрос. Вопрос в том, что "у меня есть два пушки, с которыми я могу стрелять себе в ногу, так почему мне кажется, что мне вредно стрелять в ногу третьим?"
Существование двух опасных моделей, которые нарушают безопасность типов, не делает третий такой шаблон менее опасным.
Язык и функции выполнения, которые нарушают безопасность типов, существуют в те времена, когда вы абсолютно уверены, что то, что вы делаете, безопасно, даже если компилятор этого не знает. Если вы не понимаете эти функции достаточно хорошо, чтобы безопасно их использовать, не используйте их.
Ответ 3
Я думаю, что ваша заметка о IList
указывает на то, что стоит рассмотреть здесь.
Очень полезно, что IList
реализуется массивами. Также полезно, что там есть другие коллекции, которые его реализуют.
Теперь, в эти дни, действительно в течение последних 5 лет, мы часто находили более полезным (или же полезным и безопасным) дело с IList<T>
.
До .NET2.0, однако, у нас не было IList<T>
, мы имели только IList
. Довольно много случаев, когда можно перемещаться между массивами и другими коллекциями, где fiddlier (в лучшем случае) до дженериков, которые во многих случаях теперь позволяют нам перемещаться между типизированными коллекциями и типизированными массивами с большей уверенностью.
Таким образом, аргументы в пользу ковариантных массивов были больше при принятии соответствующих решений, чем сейчас. И то, что они основываются на подобных решениях на Java, когда у него не было дженериков, только добавляет этот факт.
Ответ 4
Одна из стоимости дисперсии массива заключается в том, что присвоения массиву непечатаемого ссылочного типа немного дороже. Но учитывая, что присвоения ссылочным типам уже совсем немного связаны с GC, я предполагаю, что стоимость невелика.