Почему массив реализует 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: коллекция имела фиксированный размер" и возникла из-за того, что массив не может динамически увеличивать свою емкость. Его емкость определяется при создании объекта массива.

Другие вопросы по тегам