为啥 System.Array 类实现 IList 但不提供 Add()

Posted

技术标签:

【中文标题】为啥 System.Array 类实现 IList 但不提供 Add()【英文标题】:Why System.Array class implements IList but does not provide Add()为什么 System.Array 类实现 IList 但不提供 Add() 【发布时间】:2016-11-02 05:45:45 【问题描述】:

这段代码:

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

在构建时抛出以下错误:

错误 CS1061:“System.Array”不包含“Add”的定义,并且找不到接受“System.Array”类型的第一个参数的扩展方法“Add”(您是否缺少 using 指令或汇编参考?)

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

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

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

【问题讨论】:

如果你把它转换成IList,你就可以调用Add(类可以实现一些接口explicitly,这意味着你只能访问(全部)将其视为该接口时的接口方法)。不过你会失望的。数组有固定的大小。 那为什么语言不简单地从 Array 类签名中删除 :IList 呢? 它没有。 Array 实现了IList - 但如果你想将它作为 IList 使用,你必须将它转换为该类型的变量。 @Damien_The_Unbeliever,抱歉我更正了这个问题,我的意思是为什么它没有删除它! 这能回答你的问题吗? Why array implements IList? 【参考方案1】:

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

数组的大小是固定的,所以你不能添加新元素。

维度的数量和每个维度的长度是 在创建数组实例时建立。这些值不能 在实例的生命周期内发生变化。 https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx

为什么必须首先实现 IList?

IList的定义:表示一个非泛型的对象集合 可以通过索引单独访问。

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

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

供参考:Why array implements IList?

【讨论】:

那为什么要实现IList(有Add)? @cnom 你可以在这里看到:***.com/questions/5968708/why-array-implements-ilist【参考方案2】:

是的,如果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);

【讨论】:

【参考方案3】:

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

你得到一个编译错误的原因,相反,是因为接口是显式实现的,所以如果你想调用你需要转换为IList的方法。请参阅有关 explicit interface implementation 的 C# 指南。

【讨论】:

【参考方案4】:

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

public class MyList<T> : IList<T>

    // ... shortened for simplicity
    void ICollection<T>.Add(T item)    // explicit implementation

如果您以这种方式实现该方法,它将在MyList&lt;T&gt; 的实例上不可见:

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])。

【讨论】:

Add() 不是ICollection 的一部分 @haim770 是的:reference source 你是对的。我提到了非通用版本,它是由Array (明确)实现的【参考方案5】:

System.Array 类实现 IList 但不提供 Add()

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

为什么数组实现IList

嗯,主要是表明它支持索引器。

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

获取一个值,该值指示 IList 是否具有固定大小。

然后

固定大小的集合在集合创建后不允许添加或删除元素,但允许修改现有元素。

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

【讨论】:

谢谢!这更接近我需要的答案。我还没有接受答案,因为我想知道为什么 IList 首先被放在那里!可能有另一个接口(例如 IArray),它可能只对 IList 的 Array 成员有用 - 例如IsFixedSize、IsReadOnly、IndexOf()- 你是对的。 AFAIC BCL 设计师考虑了这些替代方案并决定走这条路。通用IList&lt;T&gt; 也一样,它也有这样的缺点。从 .NET 4.5 开始,IReadOnlyList&lt;T&gt; 最接近数组是什么(但它缺少索引器设置器)。【参考方案6】:

根据msdn:

IList.Add(对象)

调用此方法总是会引发 NotSupportedException异常。

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

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

【讨论】:

【参考方案7】:

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 类实现 IList 但不提供 Add()的主要内容,如果未能解决你的问题,请参考以下文章

为啥这些“特殊类”?

可以快速调整大小的数组

为啥我使用此 WinRT 代码得到“'System.Array' 不包含 'AsBuffer' 的定义”?

为啥 `IList<T>` 不从 `IReadOnlyList<T>` 继承?

为啥 C# 数组没有 Count 属性? [复制]

c#System.Array类的静态方法Sort()可以对一维数组进行从小到大的排序