数组的ICollection<T>.Add()-implementation是否破坏了Liskov替换原则?该方法的结果是一个NotSupportedException,它破坏了LSP,IMHO。
string[] data = new string[] {"a"};
ICollection<string> dataCollection = data;
dataCollection.Add("b");这会导致
未处理的异常: System.NotSupportedException:集合的大小是固定的。
关于Stream-implementations,我发现了一个类似的问题。我提出了一个单独的问题,因为这个案例是非常不同的:Liskov substitution principle and Streams。这里的区别是,ICollection不像Stream-class那样提供CanAdd-Property或类似的东西。
发布于 2017-05-18 13:57:46
我明白你为什么这么想了。有一个函数需要一个集合,它希望它可以修改。传递数组会使其失败,因此很明显,您不能用这个特定的实现来替换接口,对吗?
有问题吗?也许吧。这取决于你期望理想实现的频率。您是否打算使用数组而不是偶然地使用集合,然后十年后意外地发现它会崩溃呢?不怎么有意思。系统.NET应用程序使用的类型并不完美--它没有告诉您这种特定的ICollection<T>使用要求集合是可修改的。
如果数组没有假装实现ICollection<T> (或者IEnumerable<T>,它们也没有“真正”实现),那么ICollection<T>会更好吗?我不这样认为。是否有一种方法可以使数组“成为”ICollection<T>的方便,从而避免同样的LSP违规?不是的。底层数组仍然是固定长度的--充其量,您将违反更有用的原则(例如,引用类型不需要具有引用透明性)。
但是等等!让我们看一下ICollection<T>.Add的实际合同。它允许抛出一个NotSupportedException吗?哦,是的-引用MSDN:
如果. NotSupportedException被抛出。ICollection是只读的.
当查询IsReadOnly时,数组确实返回true。合同得到了维持。
如果您认为Stream不会因为CanWrite而破坏LSP,则必须考虑数组是有效的集合,因为它们有IsReadOnly,而且是true。如果一个函数接受一个只读集合并尝试添加它,那么它就是函数中的一个错误。在C#/.NET中无法显式地指定这一点,因此您必须依赖契约的其他部分,而不仅仅是类型--例如,函数的文档应该指定为只读的集合抛出NotSupportedException (或ArgumentException或其他什么)。一个好的实现将在函数开始时执行这个测试。
需要注意的一点是,在C#中,类型不像定义LSP的类型理论中那样受到约束。例如,您可以在C#中编写这样的函数:
bool IsFrob(object bobicator)
{
return ((Bob)bobicator).IsFrob;
}bobicator能被任何超类型的object取代吗?显然不是。但这显然不是糟糕的Frobinate类型的问题--它是IsFrob函数中的一个错误。实际上,C# (和大多数其他语言)中的许多代码只处理比方法签名中的类型更受约束的对象。
只有当对象违反其超级类型的契约时,它才会违反LSP。它不能对其他违反LSP的代码负责。通常,你会发现,在LSP工程中,做一些并不完美的代码是非常实用的,而且一直以来,都是关于权衡的。仔细权衡成本。
发布于 2017-05-18 13:56:12
不,因为它不是一个类--接口和实现类之间的关系不同于超类和子类之间的关系。
LSP特别适用于代码的行为,这意味着实现--接口没有实现,所以LSP不适用。
但是,这违反了接口隔离原则(),该原则要求您应该组合接口以避免未实现的方法。
https://stackoverflow.com/questions/44049593
复制相似问题