Почему массив реализует IList?
Смотрите определение класса System.Array
public abstract class Array : IList, ...
Теоретически, я должен быть в состоянии написать этот бит и быть счастливым
int[] list = new int[] {};
IList iList = (IList)list;
Я также должен иметь возможность вызывать любой метод из iList
ilist.Add(1); //exception here
Мой вопрос не в том, почему я получаю исключение, а в том, почему Array реализует IList?
8 ответов
Поскольку массив позволяет быстрый доступ по индексу, и IList
/IList<T>
Это единственные интерфейсы коллекции, которые поддерживают это. Так что, возможно, ваш реальный вопрос: "Почему нет интерфейса для постоянных коллекций с индексаторами?" И на это у меня нет ответа.
Для коллекций также нет интерфейсов только для чтения. И я скучаю по тем, что даже больше, чем постоянный размер с интерфейсом индексаторов.
ИМО, должно быть несколько (общих) интерфейсов коллекции в зависимости от особенностей коллекции. И имена тоже должны были быть разными, List
для чего-то с индексатором действительно тупое ИМО.
- Просто перечисление
IEnumerable<T>
- Только для чтения, но без индексатора (.Count,.Contains,...)
- Изменяемый размер, но без индексатора, т.е. устанавливается как (Add, Remove,...) текущий
ICollection<T>
- Только чтение с индексатором (indexer, indexof,...)
- Постоянный размер с индексатором (индексатор с установщиком)
- Переменный размер с индексатором (Insert,...) текущий
IList<T>
Я думаю, что текущие интерфейсы коллекции плохой дизайн. Но так как они имеют свойства, указывающие, какие методы являются действительными (и это является частью контракта этих методов), это не нарушает принцип подстановки.
Раздел замечаний документации для IList
говорит
IList является потомком интерфейса ICollection и является базовым интерфейсом всех неуниверсальных списков. Реализации IList делятся на три категории: только чтение, фиксированный размер и переменный размер. IList только для чтения не может быть изменен. IList фиксированного размера не позволяет добавлять или удалять элементы, но позволяет модифицировать существующие элементы. IList переменного размера позволяет добавлять, удалять и модифицировать элементы.
Очевидно, что массивы попадают в категорию фиксированного размера, так что определение интерфейса имеет смысл.
Потому что не все IList
изменчивы (см. IList.IsFixedSize
а также IList.IsReadOnly
), и массивы, безусловно, ведут себя как списки фиксированного размера.
Если ваш вопрос действительно "почему он реализует неуниверсальный интерфейс", то ответ заключается в том, что они были до появления дженериков.
Это наследие, которое мы имеем с тех времен, когда было неясно, как обращаться с коллекциями только для чтения и является ли Array доступным только для чтения. В интерфейсе IList есть флаги IsFixedSize и IsReadOnly. Флаг IsReadOnly означает, что коллекция не может быть изменена вообще, а IsFixedSize означает, что коллекция разрешает изменение, но не добавление или удаление элементов.
Во времена.Net 4.5 было ясно, что некоторые "промежуточные" интерфейсы необходимы для работы с коллекциями только для чтения, поэтому IReadOnlyCollection<T>
а также IReadOnlyList<T>
были введены.
Вот отличный пост в блоге, описывающий детали: Коллекции только для чтения в.NET
Наличие массива, реализующего IList (и, транзитивно, ICollection) упростило движок Linq2Objects, поскольку приведение IEnumerable к IList/ICollection также будет работать для массивов.
Например, Count() заканчивает внутренним вызовом Array.Length, поскольку он приведен к ICollection, а реализация массива возвращает Length.
Без этого движок Linq2Objects не имел бы специальной обработки для массивов и не работал бы ужасно, или им пришлось бы удвоить код, добавив особый режим для массивов (как они это делают для IList). Они, должно быть, решили сделать так, чтобы массив реализовал IList.
Это мой взгляд на "Почему".
Также детали реализации LINQ Последние проверки для IList, если он не реализует список, им потребуются либо 2 проверки, замедляющие все последние вызовы, либо Last на массиве, принимающем O(N)
An — это лишь одна из многих возможных реализаций .
Поскольку код должен быть слабо связанным, зависеть от абстракций, а что нет... Конкретная реализация, которая использует последовательную память (массив) для хранения своих значений, называется . Мы не «добавляем» к классу просто неправильный порядок рассуждений;
Исключением является именно то, что определяет интерфейс. Неудивительно, если вы знаете весь интерфейс, а не только один метод. Интерфейс также дает вам возможность проверить
Определение интерфейса IList: "Представляет неуниверсальную коллекцию объектов, доступ к которым по индексу возможен индивидуально". Массив полностью удовлетворяет этому определению, поэтому должен реализовывать интерфейс. Исключением при вызове метода Add() является "System.NotSupportedException: коллекция имела фиксированный размер" и возникла из-за того, что массив не может динамически увеличивать свою емкость. Его емкость определяется при создании объекта массива.