为什么数组实现 IList

本文关键字:IList 实现 数组 为什么 | 更新日期: 2023-09-27 17:56:01

参见 System.Array class 的定义

public abstract class Array : IList, ...

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

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

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

 ilist.Add(1); //exception here

的问题不是为什么我得到异常,而是为什么 Array 实现 IList

为什么数组实现 IList

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

集合也没有只读接口。而且我错过的不仅仅是带有索引器接口的恒定大小。

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

  • 只是枚举IEnumerable<T>
  • 只读但没有索引器 (.计数。包含,...)
  • 可调整大小但没有索引器,即设置为(添加,删除,...)当前ICollection<T>
  • 带索引器的只读(索引器、索引,...)
  • 带索引器的
  • 常量大小(带二传器的索引器)
  • 带索引器(插入,...)的可变大小 当前IList<T>

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

IList文档的备注部分说:

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

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

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

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

这是我们从不清楚

如何处理只读集合以及 Array 是否为只读的时代遗留下来的遗产。IList 界面中有 IsFixedSize 和 IsReadOnly 标志。IsReadOnly 标志表示集合根本无法更改,IsFixedSize 表示集合允许修改,但不允许添加或删除项目。

在 .Net 4.5 时代,很明显需要一些"中间"接口来处理只读集合,因此引入了IReadOnlyCollection<T>IReadOnlyList<T>

下面是一篇很棒的博客文章,描述了详细信息:.NET 中的只读集合

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

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

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

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

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

还有实现细节 LINQ 对 IList 的最后检查,如果它没有实现列表,他们将需要 2 次检查来减慢所有最后调用的速度,或者让 Last 在数组上取 O(N)

Array只是IList的众多可能实现之一。

由于代码应该是松散耦合的,因此依赖于抽象,而不是...使用连续内存(数组)存储其值的IList的具体实现称为 Array 。我们不会在Array类中"添加"IList,这只是错误的推理顺序; Array IList实现为数组。

例外正是接口定义的。如果您知道整个界面而不仅仅是一种方法,也就不足为奇了。该接口还使您有机会检查 IsFixedSize 属性并查看调用 Add 方法是否安全。