为什么数组要实现IList?
查看 System.Array 类的定义
public abstract class Array : IList, ...
理论上,我应该能够编写这一点并且很高兴
int[] list = new int[] {};
IList iList = (IList)list;
我也应该能够从 iList 调用任何方法
ilist.Add(1); //exception here
我的问题不是为什么我会收到异常,而是为什么 Array 实现 IList?
See the definition of System.Array class
public abstract class Array : IList, ...
Theoretically, I should be able to write this bit and be happy
int[] list = new int[] {};
IList iList = (IList)list;
I also should be able to call any method from the iList
ilist.Add(1); //exception here
My question is not why I get an exception, but rather why Array implements IList?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
因为数组允许通过索引快速访问,而
IList
/IList
是唯一支持此功能的集合接口。因此,也许您真正的问题是“为什么没有用于带有索引器的常量集合的接口?”对此我没有答案。集合也没有只读接口。我错过了那些甚至超过带有索引器接口的恒定大小的东西。
IMO 应该有更多(通用)集合接口,具体取决于集合的功能。而且名称也应该不同,在我看来,带有索引器的
List
确实很愚蠢。IEnumerable
ICollection< ;T>
IList
IList我认为当前的集合接口设计很糟糕。但由于它们具有告诉您哪些方法有效的属性(这是这些方法契约的一部分),因此它不会违反替换原则。
Because an array allows fast access by index, and
IList
/IList<T>
are the only collection interfaces that support this. So perhaps your real question is "Why is there no interface for constant collections with indexers?" And to that I have no answer.There are no readonly interfaces for collections either. And I'm missing those even more than a constant sized with indexers interface.
IMO there should be several more (generic) collection interfaces depending on the features of a collection. And the names should have been different too,
List
for something with an indexer is really stupid IMO.IEnumerable<T>
ICollection<T>
IList<T>
I think the current collection interfaces are bad design. But since they have properties telling you which methods are valid (and this is part of the contract of these methods), it doesn't break the substitution principle.
文档的备注部分 <代码> IList 说:
显然,数组属于固定大小类别,因此根据接口的定义,这是有意义的。
The remarks section of the documentation for
IList
says:Obviously, arrays fall into the fixed-size category, so by the definition of the interface it makes sense.
因为并非所有
IList
都是可变的(请参阅IList.IsFixedSize
和IList.IsReadOnly
),并且数组的行为当然就像固定大小的列表一样。如果您的问题确实是“为什么它实现非泛型接口”,那么答案是这些在泛型出现之前就已经存在了。
Because not all
IList
s are mutable (seeIList.IsFixedSize
andIList.IsReadOnly
), and arrays certainly behave like fixed-size lists.If your question is really "why does it implement a non-generic interface", then the answer is that these were around before generics came along.
这是我们从不清楚如何处理只读集合以及数组是否是只读的时代遗留下来的。 IList 接口中有 IsFixedSize 和 IsReadOnly 标志。 IsReadOnly 标志意味着集合根本无法更改,IsFixedSize 意味着集合允许修改,但不允许添加或删除项目。
在 .Net 4.5 时,很明显需要一些“中间”接口来处理只读集合,因此
IReadOnlyCollection
和IReadOnlyList
介绍了。这是一篇很棒的博客文章,描述了详细信息: 只读集合在.NET中
It's a legacy that we have from the times when it wasn't clear how to deal with read only collections and whether or not Array is read only. There are IsFixedSize and IsReadOnly flags in the IList interface. IsReadOnly flag means that collection can't be changed at all and IsFixedSize means that collection does allow modification, but not adding or removal of items.
At the time of .Net 4.5 it was clear that some "intermediate" interfaces are required to work with read only collections, so
IReadOnlyCollection<T>
andIReadOnlyList<T>
were introduced.Here is a great blog post describing the details: Read only collections in .NET
IList接口的定义是“表示可以通过索引单独访问的对象的非泛型集合”。 Array完全满足这个定义,因此必须实现该接口。
调用 Add() 方法时出现异常“System.NotSupportedException:集合具有固定大小”,这是因为数组无法动态增加其容量而发生的。它的容量是在创建数组对象时定义的。
Definition of IList interface is "Represents a non-generic collection of objects that can be individually accessed by index.". Array completely satisfies this definition, so must implement the interface.
Exception when calling Add() method is "System.NotSupportedException: Collection was of a fixed size" and occurred because array can not increase its capacity dynamically. Its capacity is defined during creation of array object.
让数组实现 IList(以及传递性的 ICollection)简化了 Linq2Objects 引擎,因为将 IEnumerable 转换为 IList/ICollection 也适用于数组。
例如,Count() 最终会在底层调用 Array.Length,因为它被转换为 ICollection 并且数组的实现返回 Length。
如果没有这个,Linq2Objects 引擎将不会对数组进行特殊处理并且执行得很糟糕,或者他们需要加倍代码来添加对数组的特殊情况处理(就像它们对 IList 所做的那样)。他们一定选择让数组实现 IList。
这就是我对“为什么”的看法。
Having an array implement IList (and transitively, ICollection) simplified the Linq2Objects engine, since casting the IEnumerable to IList/ICollection would also work for arrays.
For example, a Count() ends up calling the Array.Length under-the-hood, since it's casted to ICollection and the array's implementation returns Length.
Without this, the Linq2Objects engine would not have special treatment for arrays and perform horribly, or they'd need to double the code adding special-case treatment for arrays (like they do for IList). They must've opted to make array implement IList instead.
That's my take on "Why".
还有实现细节 LINQ Last 检查 IList ,如果它没有实现列表,它们将需要 2 个检查来减慢所有 Last 调用的速度,或者在数组上使用 Last ,时间复杂度为 O(N)
Also implementation details LINQ Last checks for IList , if it did not implement list they would need either 2 checks slowing down all Last calls or have Last on an Array taking O(N)
Array
只是IList
的众多可能实现之一。由于代码应该是松散耦合的,依赖于抽象等等...使用连续内存(数组)来存储其值的
IList
的具体实现称为Array
。我们不会“添加”IList
到Array
类,这只是错误的推理顺序;Array
将IList
实现为数组。异常正是接口定义的。如果您了解整个接口而不仅仅是单个方法,这并不奇怪。该界面还使您有机会检查
IsFixedSize
属性并查看调用Add
方法是否安全。An
Array
is just one of many possible implementations ofIList
.As code should be loosely coupled, depend on abstractions and what not... The concrete implementation of
IList
that uses consecutive memory (an array) to store it's values is calledArray
. We do not "add"IList
to theArray
class that's just the wrong order of reasoning;Array
implementsIList
as an array.The exception is exactly what the interface defines. It is not a surprise if you know the whole interface not just a single method. The interface also give you the opportunity to check the
IsFixedSize
property and see if it is safe to call theAdd
method.