为什么数组实现了IList接口?

26 浏览
0 Comments

为什么数组实现了IList接口?

查看System.Array类的定义

public abstract class Array : IList, ...

理论上,我应该能写下这段代码并且满意

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

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

 ilist.Add(1); //这里会抛出异常

我的问题不是为什么我会得到一个异常,而是为什么Array实现了IList接口

0
0 Comments

为什么数组实现了IList?

数组允许通过索引进行快速访问,而IList/IList是唯一支持这种访问方式的集合接口。所以,也许你真正的问题是“为什么没有一个带有索引器的常量集合的接口?”对此我没有答案。

同时,也没有用于集合的只读接口。我更加需要这些只读接口,比起带有索引器的常量大小的接口。

在我看来,应该有更多(泛型)集合接口,根据集合的功能来决定。而且,这些接口的名称也应该不同,List对于带有索引器的集合来说是非常愚蠢的。

  • 仅遍历 IEnumerable
  • 只读但没有索引器(.Count, .Contains,...)
  • 可调整大小但没有索引器,例如(Add, Remove,...)当前的ICollection
  • 只读带有索引器(indexer, indexof,...)
  • 常量大小带有索引器(带有setter的索引器)
  • 可变大小带有索引器(Insert,...)当前的IList

我认为目前的集合接口设计很糟糕。但是由于它们有属性告诉你哪些方法是有效的(这是这些方法的合同的一部分),所以它不会违反替代原则。

感谢你的回答。但我宁愿保留问题不变。原因很简单。接口是一个公共合同。如果一个类实现了接口,就必须完全实现所有成员,否则就会违反LSP原则,这通常是不好的,不是吗?

但是目前没有好的替代方案来替代IList,因为这是唯一一个带有索引器的集合接口。所有需要索引器的代码都使用IList,特别是许多LINQ方法(Skip、ElementAt、Reverse等)。

这确实违反了LSP。如果不违反LSP,list.Add(item)应该无论具体类型如何都会将item添加到列表中。除非有例外情况。在数组实现中,在非异常情况下会抛出异常,这本身就是不好的实践。

它不违反LSP,你只是使用方法不正确。在尝试修改对象之前,应该检查IsFixedSize或IsReadOnly。

对不起,但是你的理解是错误的。数组不实现add,因此当需要该功能时,它无法替代具有该功能的对象。

我承认,从技术上讲,它不违反LSP,只是因为文档中指出你应该检查IsFixedSize和IsReadOnly属性,但它绝对违反了“Tell, Don't Ask”原则和“最小惊讶原则”。为什么要实现一个接口,而在其中有4个方法会抛出异常呢?

一段时间过去了,但是现在在.NET 4.5中,有附加的接口IReadOnlyList和IReadOnlyCollection。

非常简单地说,这样做是为了避免破坏变更,否则人们会对此抱怨得更多。

如果检查IsReadonly或IsFixedSize,它就不会违反LSP,但会违反开放/封闭原则。在这里检查LSP:stackoverflow.com/questions/4428725/…

0
0 Comments

为什么数组实现了IList接口?

数组实现IList接口的原因是,不是所有的IList都是可变的,而数组确实表现得像固定大小的列表一样。如果您的问题实际上是“为什么它实现了一个非泛型的接口”,那么答案是在泛型出现之前,这些接口已经存在了。

不,它并没有违反LSP(Liskov Substitution Principle,里氏替换原则),因为接口IList本身告诉你它可能不可变。如果它确实保证是可变的,而数组告诉你它不是,那么才会违反这个规则。

实际上,在泛型IList的情况下,数组确实违反了LSP,而在非泛型IList的情况下却没有违反。具体可以参考这篇文章:enterprisecraftsmanship.com/2014/11/22/…

0
0 Comments

为什么数组实现了IList接口?

根据IList文档中的说明部分,我们可以得知IList是ICollection接口的子接口,也是所有非泛型列表的基础接口。IList的实现可以分为三个类别:只读、固定大小和可变大小。只读的IList不能被修改,固定大小的IList不允许添加或删除元素,但允许修改现有元素,而可变大小的IList允许添加、删除和修改元素。

很明显,数组属于固定大小的类别,所以从接口的定义上来看,数组实现IList是有意义的。

我猜他们最终会得到很多的接口,比如IListFixedSize、IListReadOnly等等,从文档的角度来看,这实际上是一个很好的答案。但对我来说,这看起来更像是一种破解方法。接口必须是简单的,以便类能够实现所有成员。

我同意。接口和运行时异常并不是最优雅的组合。为了Array的辩护,它确实显式地实现了Add方法,这降低了意外调用该方法的风险。

除非我们创建一个既禁止修改又禁止添加/删除的IList实现,那么文档将不再正确。

在.NET 4.5中,还有额外的接口IReadOnlyList和IReadOnlyCollection。但据我所知,遗憾的是没有相反的接口来排除不能被写入的集合。

除非你试图公开一个接口,以免强制要求具体实现。

0