为什么 System.Array class 实现了 IList 但不提供 Add()

Why System.Array class implements IList but does not provide Add()

此代码:

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

在构建时抛出以下错误:

error CS1061: 'System.Array' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)

IList接口有Add()方法,为什么Array没有实现?

更新:我从答案中看到它确实明确地实现了它,好的,我明白了,谢谢,我应该更好地坚持这个问题:

为什么 Array 实际上 没有提供 Add(),或者,更好的是,为什么它首先要实现 IList ?它可以是另一个接口(例如 IArray),而不是实现 IList,它可能只对 IList 的数组成员有用 - 例如IsFixedSizeIsReadOnlyIndexOf()...只是一个想法。

为什么Array实际上没有提供Add()?

数组具有固定大小,因此您不能添加新元素。

The number of dimensions and the length of each dimension are established when the array instance is created. These values can't be changed during the lifetime of the instance. https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx

为什么它首先要实现 IList?

Definition of IList: Represents a non-generic collection of objects that can be individually accessed by index.

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

Array 是通过索引访问的,而 IList 容纳了这个索引,这就是 Array 实现 IList 的原因。

供参考:Why array implements IList?

它确实提供了Add,但是通过抛出一个NotSupportedException(参见MSDN),因为数组的大小是固定的。

之所以会出现编译错误,是因为接口是显式实现的,所以如果要调用需要强制转换为 IList 的方法。请参阅有关 explicit interface implementation.

的 C# 指南

虽然实现接口的 class 必须实现接口的所有成员,但它可以显式实现它们:

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 因为 数组有固定大小 而你不能 add数组的新元素,因为它的大小在初始化时确定 (new int[0])。

根据msdn:

IList.Add(Object)

Calling this method always throws a NotSupportedExceptionexception.

Array Class - 参见显式接口实现部分

Array有这个方法。要调用此方法,您应该显式转换为 IList。无法调用此方法,因为数组的大小是固定的,无法动态更改。

IList 在三个不同的类别中实现:

  • 只读
  • 可变大小
  • 固定尺寸

显然 Array 类型是 IList 的固定大小实现。 您无法从 Array 访问 Add() 方法的原因是因为该方法是显式实现的:

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

这意味着您需要先将数组转换为 IList,然后才能使用 Add 方法(即使它会抛出不受支持的异常)。

你可能会说这是一个糟糕的设计,很多人会同意你的看法。

阅读有关显式定义接口的更多信息: https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

System.Array class implements IList but does not provide Add()

当然是通过显式实现实现的(没有办法实现接口而不实现某些成员)。

Why the array implements IList?

嗯,主要是说明它支持indexer。

但实际上数组实现了一种有效的 IList 用法。 IList 接口有一个名为 IsFixedSize 的 属性,根据文档

Gets a value indicating whether the IList has a fixed size.

然后

A collection with a fixed size does not allow the addition or removal of elements after the collection is created, but it allows the modification of existing elements.

所以数组实现 returns IsFixedSize = true 并在 AddInsertRemoveRemoveAt 方法中抛出 NotSupportedException .

是的,如果 System.Array 实现了 IReadOnlyList 或类似的接口,似乎应该是一个更好的设计。然而,IReadOnlyList<T>出现在.Net 4.5中,而System.Array保留在最初的.Net 1.0中。微软,恕我直言,尽了最大努力,并通过 显式接口实现

隐藏 Add

http://referencesource.microsoft.com/#mscorlib/system/array.cs,156e066ecc4ccedf

  ...
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);
}