Почему класс 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