参见System.Array类的定义
public abstract class Array : IList, ...
理论上我应该能写到这点并且开心
int[] list = new int[] {};
IList iList = (IList)list;
我也应该能够从 iList 调用任何方法
ilist.Add(1); //exception here
我的问题不是为什么我得到一个异常,而是为什么 Array 实现 IList?
参见System.Array类的定义
public abstract class Array : IList, ...
理论上我应该能写到这点并且开心
int[] list = new int[] {};
IList iList = (IList)list;
我也应该能够从 iList 调用任何方法
ilist.Add(1); //exception here
我的问题不是为什么我得到一个异常,而是为什么 Array 实现 IList?
因为数组允许通过索引快速访问,并且IList
/IList<T>
是唯一支持此操作的集合接口。所以也许你真正的问题是“为什么没有索引器的常量集合接口?” 对此我没有答案。
集合也没有只读接口。而且我缺少的不仅仅是带有索引器界面的恒定大小。
IMO 应该有更多(通用)集合接口,具体取决于集合的功能。名称也应该不同,List
因为带有索引器的东西真的很愚蠢 IMO。
IEnumerable<T>
ICollection<T>
IList<T>
我认为当前的集合界面设计不佳。但是因为它们有属性告诉你哪些方法是有效的(这是这些方法契约的一部分),它不会违反替换原则。
文档的备注部分IList
说:
IList 是 ICollection 接口的后代,是所有非泛型列表的基接口。 IList 实现分为三类:只读、固定大小和可变大小。无法修改只读 IList。固定大小的 IList 不允许添加或删除元素,但允许修改现有元素。可变大小的 IList 允许添加、删除和修改元素。
显然,数组属于固定大小的类别,因此通过接口的定义是有意义的。
因为并非所有IList
的 s 都是可变的(参见IList.IsFixedSize
和IList.IsReadOnly
),并且数组的行为当然类似于固定大小的列表。
如果您的问题真的是“为什么它实现非泛型接口”,那么答案是这些在泛型出现之前就已经存在。
这是我们从不清楚如何处理只读集合以及 Array 是否为只读的时代遗留下来的。IList 接口中有 IsFixedSize 和 IsReadOnly 标志。IsReadOnly 标志表示完全不能更改集合,而 IsFixedSize 表示集合确实允许修改,但不允许添加或删除项目。
在 .Net 4.5 的时候,很明显需要一些“中间”接口来处理只读集合,因此IReadOnlyCollection<T>
引入IReadOnlyList<T>
了。
这是一篇描述详细信息的精彩博客文章:Read only collections in .NET
IList 接口的定义是“表示可以通过索引单独访问的对象的非泛型集合。”。数组完全满足这个定义,所以必须实现接口。调用 Add() 方法时的异常是“System.NotSupportedException:Collection was a fixed size”并且由于数组无法动态增加其容量而发生。它的容量是在创建数组对象时定义的。
让数组实现 IList(以及可传递的 ICollection)简化了 Linq2Objects 引擎,因为将 IEnumerable 转换为 IList/ICollection 也适用于数组。
例如,Count() 最终会在后台调用 Array.Length,因为它被强制转换为 ICollection 并且数组的实现返回 Length。
如果没有这个,Linq2Objects 引擎将不会对数组进行特殊处理并且性能会很糟糕,或者他们需要将代码加倍,为数组添加特殊情况处理(就像他们为 IList 所做的那样)。他们一定选择让数组实现 IList。
这就是我对“为什么”的看法。
还有实现细节 LINQ Last 检查 IList ,如果它没有实现 list 他们将需要 2 次检查减慢所有 Last 调用或 Last 上的 Array 采用 O(N)