为什么数组实现 IList?

请参阅 系统数组类的定义

public abstract class Array : IList, ...

理论上讲,我应该能够写这一点,并感到高兴

int[] list = new int[] {};
IList iList = (IList)list;

我还应该能够从 iList 调用任何方法

 ilist.Add(1); //exception here

我的问题不是为什么我得到一个例外,而是 为什么 Array 实现 IList

30565 次浏览

因为数组允许按索引快速访问,而 IList/IList<T>是支持这一点的唯一集合接口。因此,也许您真正的问题是“为什么没有用于具有索引器的常量集合的接口?”对此我没有答案。

集合也没有只读接口。我错过了这些甚至比一个常量大小与索引器接口。

根据集合的特性,应该有几个更多的(通用的)集合接口。而且名称也应该不同,List的东西与索引器是真正愚蠢的 IMO。

  • 只是枚举 IEnumerable<T>
  • 只读但没有索引器(. Count,. Contains,...)
  • 可调整大小但没有索引器,即设置为(添加,删除,...)当前 ICollection<T>
  • 只读的 indexer (indexer,indexof,...)
  • 带有 indexer 的常数大小(带有 setter 的 indexer)
  • 可变大小与索引器(插入,...)当前 IList<T>

我认为当前的集合接口设计得很糟糕。但是因为它们有属性告诉你哪些方法是有效的(这是这些方法契约的一部分) ,所以它不会打破替换原则。

文件IList的备注部分写道:

IList 是 接口,并且是基 所有非通用列表的接口。 IList 的实现分为三类 类别: 只读、固定大小和 可变大小 . 只读 IList 无法修改。固定大小的 IList 不允许添加或删除 元素,但它允许 修改现有的元素 可变大小的 IList 允许 添加、去除和修改 元素。

显然,数组属于固定大小的类别,因此根据接口的定义,它是有意义的。

因为 并非所有的 IList都是可变的(参见 IList.IsFixedSizeIList.IsReadOnly)和数组的行为当然像固定大小的列表。

如果你的问题真的是“为什么它实现了一个 非通用的接口”,那么答案是这些接口在泛型出现之前就已经存在了。

IList 接口的定义是“表示可以通过索引单独访问的对象的非通用集合”.数组完全满足此定义,因此必须实现接口。 调用 Add ()方法时发生异常。集合的大小是固定的”,因为数组不能动态增加其容量而发生。它的容量是在创建数组对象时定义的。

这是一个遗产,我们从时代,它不清楚如何处理只读集合和是否数组是只读。IList 接口中有 IsFixedSize 和 IsReadOnly 标志。IsReadOnly 标志意味着集合根本不能更改,而 IsFixedSize 意味着集合允许修改,但不允许添加或删除项。

当时。Net 4.5显然需要一些“中间”接口来处理只读集合,因此引入了 IReadOnlyCollection<T>IReadOnlyList<T>

下面是一篇描述细节的博客文章: 在.NET 中只读集合

使用数组实现 IList (以及传递性的 ICollection)简化了 Linq2Objects 引擎,因为将 IEnumable 转换为 IList/ICollection 也适用于数组。

例如,Count ()最终调用 Array。底层的长度,因为它被强制转换为 ICollection,并且数组的实现返回 Llength。

如果没有这个特性,Linq2Objects 引擎就不会对数组进行特殊处理并且执行得很糟糕,或者它们需要加倍为数组添加特殊处理的代码(就像它们对 IList 所做的那样)。他们一定是选择了让数组实现 IList。

这就是我对“为什么”的看法。

另外实现细节 LINQ IList 的最后检查,如果它没有实现列表,他们将需要2个检查来减慢所有 Last 调用的速度,或者数组中的 Last 采用 O (N)