goe*_*ing 20 c# collections frameworks liskov-substitution-principle
查看ReadOnlyCollection类的规范,它确实实现了IList接口.
IList接口具有Add/Update/Read方法,我们称之为接口的前置条件.在我的应用程序的任何地方,如果我有一个IList我应该能够做所有这些操作.
但是,如果我在代码中的某处返回ReadOnlyCollection并尝试调用.Add(...)方法呢?它会抛出NotSupportedException.你认为这是一个糟糕设计的好例子吗?另外,这个类是否打破了Liskov替换原则?
为什么Microsoft以这种方式实现?是否更容易(和更好)使这个ReadOnlyCollection只实现IEnumerable接口(顺便说一下,已经只读)?
Tim*_*mwi 10
是的,确实是糟糕的设计..NET中缺少集合接口:没有只读接口.
您是否知道string[]实现IList<string>(和其他类型的同上)?这有同样的问题:你会期望你可以调用Add和Remove在界面上,但它会抛出.
不幸的是,在不破坏向后兼容性的情况下,这不能再改变了,但我同意你的看法,这是非常糟糕的设计.更好的设计可以看到用于只读功能的单独接口.
虽然IList<T>接口定义Add(T)和Insert(int,T)方法,但它也定义了IsReadOnly属性,如果你仔细阅读MSDN上的IList.Insert(int,T)和IList.Add(T)方法的定义,你可以看到它们都指定NotSupportedException如果列表是只读.
说因为这个原因设计不好就像是说它设计也不好,因为当索引为负数或大于集合大小时Insert(int, T)可以抛出ArgumentOutOfRangeException.
在我看来,这不是一个伟大的设计,而是必然的邪恶。
不幸的是,Microsoft没有在框架中包含IReadableList<>和IWriteableList<>,并且IList<>自己实现了两者(或者甚至IList<>完全跳过并IWriteableList<>实现了IReadableList<>)。问题解决了。
但是现在进行更改为时已晚,如果您遇到一种情况,需要集合具有列表语义,并且您希望在运行时抛出异常而不是允许进行突变,那么ReadOnlyCollection<>不幸的是,这是您的最佳选择。
Kir*_*irk -3
我认为如果有一个糟糕的设计,那就是在不检查 ReadOnly 属性的情况下添加到 IList 的习惯。程序员忽略接口部分的习惯并不意味着接口很差。
事实上,我们程序员中很少有人会费心去阅读规范。说实话,对我来说,有很多事情比坐下来阅读整个规范文档更令人兴奋。(例如,看看一个人是否真的可以用牙签睁开眼睛。)此外,我还有一个限制,那就是我无论如何都不会记住所有事情。
话虽如此,在不至少查看属性和方法列表的情况下,不应使用接口。您认为名为“ReadOnly”的布尔属性的用途是什么?也许是因为该列表只能出于某种原因而被读取。如果您要获取从您自己的代码之外的某个地方传递的列表,您应该在尝试添加列表之前检查该列表是否是只读的。