当前位置: 首页 > 知识库问答 >
问题:

Liskov代换原理与接口

洪昱
2023-03-14

是否ICollection

string[] data = new string[] {"a"};
ICollection<string> dataCollection = data;
dataCollection.Add("b");

这导致

未处理的异常:System.集合的大小是固定的。

我发现了一个关于-实现的非常类似的问题。我打开一个单独的问题,因为这个案例非常不同:Liskov替换原理和流。这里的区别在于,ICollection没有像-类那样提供CanAdd-属性或类似的东西。


共有2个答案

洪季萌
2023-03-14

不,因为它不是一个类-接口和实现类之间的关系与超级类和子类之间的关系不同。

LSP特别适用于暗示实现的代码行为——接口并没有实现,所以LSP不适用。

然而,这违反了接口隔离原则,即您应该编写接口以避免未实现的方法。

仉昂熙
2023-03-14

我明白你为什么这么想。有一个函数需要一个集合,并且它希望集合是可修改的。传递一个数组会使它失败,所以很明显,您不能用这个特定的实现来替代接口,对吗?

这是个问题吗?大概这取决于你期望理想保持多久。你是不是打算用一个数组而不是一个偶然的集合,然后在十年后惊讶于它崩溃了?不是真的。类型系统。NET应用程序的使用并不完美-它没有告诉您这个特定的ICollection

将如果数组不假装实现ICollection,NET可能会更好

但是等等!让我们看一下ICollection的实际合同

[如果…,则引发NotSupportedException]ICollection是只读的。

当您查询IsReadOnly时,数组确实返回true。合同得以维持。

如果您认为Stream不会因为CanWrite而破坏LSP,那么您必须将数组视为有效的集合,因为它们具有IsReadOnly,并且它是true。如果函数接受只读集合并尝试向其添加,则该函数中存在错误。没有办法在C#/中显式地指定它。NET,因此您必须依赖合同的其他部分,而不仅仅是类型-例如,函数的留档应该指定为只读集合抛出NotSupport dExc0019(或ArgumentExc0019或其他任何内容)。一个好的实现应该在函数开始时就做这个测试。

需要注意的一点是,C#中的类型并不像定义LSP的类型理论那样受到约束。例如,您可以在C#中编写这样的函数:

bool IsFrob(object bobicator)
{
  return ((Bob)bobicator).IsFrob;
}

可以bobicator取代任何超类型的对象?显然不是。但这显然不是糟糕的Frobate类型的问题,而是IsFrob函数中的错误。在实践中,C#(和大多数其他语言)中的许多代码只适用于比方法签名中的类型所指示的约束大得多的对象。

对象只有在违反其超类型的约定时才违反LSP。它不能对违反LSP的其他代码负责。通常,您会发现,在LSP下,编写不完美的代码是非常实用的——工程是,而且一直是,关于权衡。仔细权衡成本。

 类似资料:
  • 存在无法写入或查找的流派生类这一事实是否违反了Liskov替换原则? 例如,无法查找NetworkStream,如果调用方法,它将抛出。 还是因为存在标志就可以了? 考虑到众所周知的继承自的例子...将标志和添加到是否可以解决问题? 这难道不是打开了通过添加旗帜来解决问题的大门吗?

  • 我在派生类中重写了带有附加先决条件的虚拟函数。这是快照- 如果我理解正确的话,这里的代码通过附加一个先决条件打破了Liskov替换-IsImmediateProcess和其他日期检查。对吗?或者一个被重写的函数调用一个基函数,然后向它添加自己的行为,这样可以吗? 我不能将重写方法中由初始过程类型引入的条件移动到基本类型,因为它是特定于初始过程的。 在这种情况下,如果派生类重写行为并希望在不违反Li

  • 我试图理解Liskov替换原理,我有以下代码: 我不确定这是否违反了它。原理是,如果你有一个类S的对象,那么你可以用另一个类T的对象来代替它,其中S是T的一个子类。但是,如果我写了 这当然会产生编译错误,因为Vehicle类没有openDoor()方法。但这意味着我不能用它们的父类Vehicle替换VehicleWithDoors对象,这似乎违反了原则。那么这个代码是否违反了它?我需要一个好的解释

  • 在创建我的班级结构时,我努力坚持利斯科夫替代原则。我想在Day类中存储一组日历项。需要有几种不同类型的日历项,例如: 任命项目 备注项目 轮换项目 它们都共享一些抽象基类CalendarItem中的常见功能: 但例如RotaItem有一些额外的功能: 其他类也添加了自己的逻辑等。 我有一组CalendarBaseItem用于我的日课: 但在回顾这一点时,我可以看到我正在打破LSP原则,因为我必须检

  • 我在理解这两个原则时有些困难。这是一个有点长的阅读问题,所以要有耐心。 假设我们有一个类 和接口 然后我们创建了两个子类 现在我们将使implements 并在儿童课程中做出改变 并为该结构创建测试函数(如下LSP): 在这里我想停下来,因为实际上在下一步我被绊倒了。如果我们要创建第三个类? 圆没有边,所以为这个孩子实现听起来很可笑。好的,我们可以只将实现移到四边形和三角形,但在这种情况下LSP将

  • 我试图通过反复阅读维基百科条目来确定我对上述原则的理解。 撇开仍然让我悲伤的协变和逆变的概念不谈,wikipedia还提到超类型的不变量必须保留在子类型和历史约束或历史规则中。基于最后两个概念,我提出了一个小例子: 所以我的问题是:基于上述两个概念,我用这个例子是否违反了原则?若否,原因为何? 事先非常感谢。