Why array implements IList?
参见System.Array类的定义
1
| public abstract class Array : IList, ... |
从理论上讲,我应该能够写下这一点并且感到快乐
1 2
| int[] list = new int[] {};
IList iList = (IList )list ; |
我还应该能够从IList调用任何方法
1
| ilist.Add(1); //exception here |
我的问题不是为什么我会得到一个异常,而是为什么数组实现了IList?
- 问得好。我从不喜欢胖接口的概念(这是这种设计的技术术语)。
- 真正(更好)的问题是为什么它支持IList。IList是遗产。
- 你认为它如何打破替代?我想没有。看布赖恩的回答。
- @Henk,参见:blogs.msdn.com/b/bclteam/archive/2004/11/19/267089.aspx
- 有人真的关心LSP吗?我觉得这很学术。
- @加布,那么你需要处理更大的代码基。实现一个行为(从一个接口继承),然后简单地忽略你不喜欢/不支持的东西,这会导致恶臭、模糊、强制转换,最后是错误代码。
- @马吕斯:你必须把复杂性放在某个地方。假设您有一个方法可以对其类的成员进行排序。使用单个IList<>接口,您可以检查IsReadOnly以查看是否可以排序。如果您有单独的IRWList<>和IReadList<>接口,那么您将什么类型的接口作为类的成员?您不能使用IRWList<>,因为这样它就不能容纳只读对象,所以您必须将其设置为IReadList<>,然后强制转换为IRWList,以进行排序。看——难闻的,模糊的铸件。
- @它的集合意味着易变性,而不是它所包含的实体。您可以将类成员设置为同时实现irwlist<>和ireadlist<>的类型,在类内部使用if as irwlist<>并将其公开为ireadlist。是的,你必须把复杂性放在某个地方,但我不明白忽视LSP作为一个很好的设计原则是如何适用的(不知道IsreadOnly属性,尽管从消费者的角度来看,这使得iList更加复杂)
因为数组允许按索引快速访问,所以只有IList/IList是支持此功能的集合接口。因此,您真正的问题可能是"为什么没有索引器的常量集合接口?"对此我没有答案。
集合也没有只读接口。我甚至错过了一个比索引器接口更大的常量。
IMO根据集合的特性,应该有多个(通用)集合接口。而且名字也应该是不同的,在我看来,使用索引器的List是很愚蠢的。
- 仅列举IEnumerable。
- 只读,但没有索引器(.count,.contains,…)
- 可调整大小但没有索引器,即设置为(添加、删除等)当前ICollection。
- 使用索引器只读(indexer,indexof,…)
- 带索引器的常量大小(带设置器的索引器)
- 带索引器(insert,…)的可变大小当前IList。
我认为当前的收集接口设计不好。但是,因为它们的属性告诉您哪些方法是有效的(这是这些方法的契约的一部分),所以不会破坏替换原则。
- 谢谢你的回答。但我宁愿不提这个问题。原因很简单。接口是公共合同。如果实现了它,就必须完全实现所有的成员,否则它会破坏LSP,并且通常有异味,不是吗?
- @但没有好的替代方法来替代IListATM,因为这是唯一一个带索引器的收集接口。因此,所有需要索引器的代码都使用IList,特别是许多linq方法(skip、elementat、reverse,…)
- 它确实会破坏LSP。如果没有列出,则添加(项)应将项添加到列表中,而不管具体类型如何。例外情况除外。在数组实现中,在非异常的情况下引发异常,这本身就是一种不好的做法。
- 是否有某种语言的core+库能够正确地获取这些集合?我注意到,Clojure的作者在使事物一致性方面做了大量的思考,但是Clojure是一个完全不同的平台。
- 参见blogs.msdn.com/b/andrewarnottms/archive/2011/08/22/&hellip;
- @runefs它不会破坏lsp,你只是用错了。在尝试改变对象之前,应该检查isFixedSize或isReadOnly。
- @斯梅尔奇,我很抱歉,但是你弄错了LSP。一个数组不实现add,因此当需要这种能力时,它不能被替代。
- 我承认,它在技术上并没有违反LSP,仅仅是因为文件规定你应该检查IsFixedSize和IsReadOnly的属性,它肯定违反了告诉,不要问原则和最不吃惊的原则。当您只想抛出9个方法中的4个的异常时,为什么要实现一个接口?
- 从最初的问题开始已经过了一段时间。但是现在有了.NET 4.5,就有了其他接口IReadOnlyList和IReadOnlyCollection。
- 很简单,这样做是为了避免破坏变化,人们会抱怨比这更多的声音。
- 如果选中isreadonly或isfixedsize,它不会破坏lsp,但会违反打开/关闭。查看lsp here stackoverflow.com/questions/4428725/&hellip;
IList文件的备注部分说
IList is a descendant of the
ICollection interface and is the base
interface of all non-generic lists.
IList implementations fall into three
categories: read-only, fixed-size, and
variable-size. A read-only IList
cannot be modified. A fixed-size IList
does not allow the addition or removal
of elements, but it allows the
modification of existing elements. A
variable-size IList allows the
addition, removal, and modification of
elements.
显然,数组属于固定大小的类别,因此通过定义接口,它是有意义的。
- 我想他们最终会有很多接口。ilistFixedSize,ilistreadoonly…
- 从文档的角度来看,这实际上是一个很好的答案。但对我来说,它更像一个黑客。接口必须薄且简单,以便类实现所有成员。
- @我同意。接口和运行时异常并不是最优雅的组合。为了防御Array的攻击,它确实显式地实现了add方法,从而降低了意外调用该方法的风险。
- 直到我们创建一个不允许修改和添加/删除的IList的实现。那么这些文件就不再是正确的了。P
- @magnus-在.NET 4.5中,还有其他接口ireadOnlyList和ireadOnlyCollection。
因为并不是所有的IList都是可变的(见IList.IsFixedSize和IList.IsReadOnly),数组的行为肯定像固定大小的列表。
如果您的问题真的是"为什么它实现了一个非泛型接口",那么答案是,这些接口在泛型出现之前就已经存在了。
- @不,它不会破坏LSP,因为接口IList本身告诉您它可能不可变。如果它实际上被保证是可变的,并且数组告诉了您其他情况,那么它将打破规则。
- 实际上,array在普通IList的情况下会破坏lsp,而在非普通IList的情况下不会破坏lsp:enterprisecraftsmanship.com/2014/11/22/&hellip;
这是我们从不清楚如何处理只读集合以及数组是否为只读的时代留下的遗产。在IList接口中有isFixedSize和isReadOnly标志。isreadOnly标志表示集合根本无法更改,isFixedSize表示集合允许修改,但不允许添加或删除项。
在.NET 4.5时代,很明显需要一些"中间"接口来处理只读集合,因此引入了IReadOnlyCollection和IReadOnlyList。
下面是一篇描述详细信息的很棒的博客文章:在.NET中的只读集合
IList接口的定义是"表示可由索引单独访问的非通用对象集合"。数组完全满足这个定义,因此必须实现接口。调用add()方法时发生异常:"System.NotSupportedException:集合的大小固定",原因是数组无法动态增加其容量。它的容量是在创建数组对象期间定义的。