为什么数组实现IList?

时间:2011-05-11 18:15:19

标签: c# arrays ilist liskov-substitution-principle

请参阅 System.Array

的定义
public abstract class Array : IList, ...

理论上,我应该能够写下这一点并且开心

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

我也应该可以从iList中调用任何方法

 ilist.Add(1); //exception here

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

7 个答案:

答案 0 :(得分:89)

因为数组允许通过索引快速访问,IList / IList<T>是唯一支持此功能的集合接口。所以也许你真正的问题是“为什么没有用于索引器的常量集合的接口?”对此我没有答案。

也没有集合的只读接口。而且我还缺少那些带有索引器界面的常量大小。

IMO应该有几个(通用)集合接口,具体取决于集合的功能。并且名称应该也不同,List对于带有索引器的东西来说真是愚蠢的IMO。

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

我认为当前的集合接口是糟糕的设计。但由于它们具有告诉您哪些方法有效的属性(这是这些方法的合同的一部分),因此它不会破坏替换原则。

答案 1 :(得分:38)

IList {{1}}的评论部分说

  

IList是该家族的后裔   ICollection接口是基础   所有非通用列表的接口。    IList实现分为三个   类别:只读,固定大小和   可变大小的即可。只读IList   无法修改。固定大小的IList   不允许添加或删除   元素,但它允许   修改现有元素。一个   可变大小的IList允许   添加,删除和修改   元件。

显然,数组属于固定大小的类别,因此通过界面的定义,它是有意义的。

答案 2 :(得分:17)

因为并非所有IList都是可变的(请参阅IList.IsFixedSizeIList.IsReadOnly),并且数组的行为肯定与固定大小的列表相同。

如果您的问题确实是“为什么它实现了非通用接口”,那么答案就是这些问题在仿制药出现之前就已存在。

答案 3 :(得分:4)

这是我们从那时尚未清楚如何处理只读集合以及Array是否只读的时代的遗产。 IList接口中有IsFixedSize和IsReadOnly标志。 IsReadOnly标志意味着集合根本无法更改,IsFixedSize意味着集合允许修改,但不允许添加或删除项目。

在.Net 4.5时,很明显有些&#34;中间&#34;接口需要与只读集合一起使用,因此引入了IReadOnlyCollection<T>IReadOnlyList<T>

这是一篇很棒的博客文章,描述了详细信息:Read only collections in .NET

答案 4 :(得分:0)

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

答案 5 :(得分:0)

具有数组实现IList(以及可传递的ICollection)简化了Linq2Objects引擎,因为将IEnumerable强制转换为IList / ICollection也适用于数组。

例如,一个Count()最终调用了Array.Length,因为它被强制转换为ICollection并且该数组的实现返回Length。

没有这些,Linq2Objects引擎将不会对数组进行特殊处理并表现出可怕的效果,或者它们需要加倍对数组添加特殊情况处理的代码(就像对IList所做的那样)。他们必须选择使数组实现IList。

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

答案 6 :(得分:0)

实现细节LINQ Last检查IList,如果它没有实现list,他们将需要进行2次检查以减慢所有Last调用的速度,或者需要将Last放在具有O(N)的数组上