Почему класс System.Array реализует IList, но не предоставляет Add()

Этот код:

int[] myArr = { 1, 2 };
myArr.Add(3);

бросает на Build:

Ошибка CS1061: "System.Array" не содержит определения для "Add", и нет метода расширения "Add", принимающего первый аргумент типа "System.Array" (вы пропустили директиву using или ссылку на сборку?)

IList интерфейс имеет Add() метод, но почему Array не реализует его?

ОБНОВЛЕНИЕ: я вижу из ответов, что это действительно реализует это, хорошо, я понимаю, спасибо, я должен лучше придерживаться вопроса:

Зачем Array на самом деле не обеспечивает Add()ИЛИ лучше, зачем это нужно было реализовывать IList на первом месте? Вместо реализации IList, это может быть другой интерфейс (например, IArray) который может иметь ТОЛЬКО полезное для массива членов IList -например IsFixedSize, IsReadOnly, IndexOf()... просто мысль.

7 ответов

Решение

Да, кажется, что это должен был быть лучший дизайн, если System.Array реализовал IReadOnlyList или похожий интерфейс. Тем не мение, IReadOnlyList<T> появился в .Net 4.5 в то время как System.Array остается от первоначального .Net 1.0. Microsoft, ИМХО, постаралась и спряталась Add через явную реализацию интерфейса

http://referencesource.microsoft.com/

  ...
int IList.Add(Object value)
{
    throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
} 
  ...

Так что вы не можете сделать

int[] myArr = { 1, 2 };

myArr.Add(3);

но вы можете настаивать на использовании Add (и получить NotSupportedException брошенный) через

((IList) myArr).Add(3);

Или даже

if (!myArr.IsFixedSize) {
  // we have very strange array, let's try adding a value to it
  ((IList) myArr).Add(3);
}

Почему Array на самом деле не предоставляет Add()?

Массив имеет фиксированный размер, поэтому вы не можете добавлять новые элементы.

Количество измерений и длина каждого измерения определяются при создании экземпляра массива. Эти значения не могут быть изменены во время жизни экземпляра. https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx

Почему в первую очередь нужно было внедрить IList?

Определение IList: представляет собой неуниверсальную коллекцию объектов, доступ к которым по индексу возможен индивидуально.

https://msdn.microsoft.com/en-us/library/system.collections.ilist.aspx

Доступ к массиву осуществляется по индексу, и IList учитывает этот индекс, поэтому Array реализует IList.

Для справки: почему массив реализует IList?

Хотя класс, реализующий интерфейс, должен реализовывать все члены интерфейса, он может реализовать их явно:

public class MyList<T> : IList<T>
{
    // ... shortened for simplicity
    void ICollection<T>.Add(T item) {  } // explicit implementation
}

Если вы реализуете метод таким образом, он не будет виден в случаях MyList<T>:

MyList<int> list = new MyList<int>();
list.Add(5); // would NOT compile
((IList<int>)list).Add(5); // can be compiled

Так что если у вас есть int[] Вы могли бы сделать это:

int[] array = new int[0];
((IList<int>)array).Add(5);

Он скомпилируется, но во время выполнения NotSupportedException будет выброшено, потому что массивы имеют фиксированный размер, и вы не можете добавить новый элемент в массив, так как его размер определяется при инициализации (new int[0]).

Это обеспечивает Добавить, но, бросая NotSupportedException (см. MSDN), потому что размер массива фиксирован.

Причина, по которой вы получаете ошибку компиляции, заключается в том, что интерфейс реализован явно, поэтому, если вы хотите вызвать метод, вам нужно привести к IList, Смотрите это руководство C# о явной реализации интерфейса.

Класс System.Array реализует IList, но не предоставляет Add()

Конечно, это происходит через явную реализацию (нет способа реализовать интерфейс и не реализовать некоторые члены).

Почему массив реализует IList?

Ну, в основном, чтобы указать, что он поддерживает индексатор.

Но на самом деле массив реализует один из действительных IList обыкновения. IList интерфейс имеет свойство под названием IsFixedSize который согласно документации

Получает значение, указывающее, имеет ли IList фиксированный размер.

а потом

Коллекция с фиксированным размером не позволяет добавлять или удалять элементы после создания коллекции, но позволяет изменять существующие элементы.

Так что реализация массива возвращает IsFixedSize = true и бросает NotSupportedException внутри Add, Insert, Remove а также RemoveAt методы.

Согласно MSDN:

IList.Add (Объект)

Вызов этого метода всегда вызывает исключение NotSupportedException.

Array Class - см. Раздел реализации явного интерфейса

Array имеет этот метод. Чтобы вызвать этот метод, вы должны явно привести к IList, Этот метод не может быть вызван, потому что массив имеет фиксированный размер и этот размер не может быть изменен динамически.

IList реализован в трех разных категориях:

  • Readonly
  • Переменный размер
  • Исправленный размер

Очевидно, что Array Тип является реализацией фиксированного размера IList, Причина, по которой вы не можете получить доступ к Add() метод из Array потому что метод реализован явно:

public class A : IList {
    public void IList.Add(object o){
         ...
    }
}

Это означает, что вам нужно привести ваш массив к IList прежде чем вы сможете использовать Add метод (даже если он выдаст неподдерживаемое исключение).

Вы можете сказать, что это плохой дизайн, и многие люди согласятся с вами по этому поводу.

Узнайте больше о явно определенных интерфейсах: https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

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