Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当继承一个类伤害你以后?_C#_Inheritance_Oop - Fatal编程技术网

C# 当继承一个类伤害你以后?

C# 当继承一个类伤害你以后?,c#,inheritance,oop,C#,Inheritance,Oop,当我们从一个类继承时,它可以工作一段时间,但是其他的东西发生了变化并引入了一个bug,您能提供一些场景吗? 我想到了以下情况: 为了实现带孔矩形,我们从类Rectangle继承。在构造函数中,我们检查孔是否位于矩形内 后来有人向类Rectangle添加了一个新方法Resize。他们不会检查洞是否还在里面 调整大小后,我们可以有一个带有孔的矩形,但孔不在矩形内,这是一个bug 如果我选择在C#中使用对象继承,我还应该注意哪些问题 您所描述的是继承的陷阱之一 另一个陷阱是深层继承层次结构。Sta

当我们从一个类继承时,它可以工作一段时间,但是其他的东西发生了变化并引入了一个bug,您能提供一些场景吗? 我想到了以下情况:

  • 为了实现带孔矩形,我们从类Rectangle继承。在构造函数中,我们检查孔是否位于矩形内
  • 后来有人向类Rectangle添加了一个新方法Resize。他们不会检查洞是否还在里面
  • 调整大小后,我们可以有一个带有孔的矩形,但孔不在矩形内,这是一个bug

如果我选择在C#中使用对象继承,我还应该注意哪些问题

您所描述的是继承的陷阱之一


另一个陷阱是深层继承层次结构。Stackoverflow线程打开。

不要在构造函数中调用虚方法。请参阅Eric Lippert关于它的帖子(和)。

这被称为


一般来说,继承的另一个潜在问题是,您希望使用自己的基类,但框架需要特定的基类(例如,
ContextBoundObject
)而不是接口

基类的更改有很多种方式可以影响派生类的行为。例如,如果作者突然决定将类密封起来怎么办

与任何接口一样,如果用户不需要修改,它需要稳定

继承的主要“规则”是Liskov替代原则。这说明派生类应该可以替换基类或从它派生的其他类

这种情况在表面上违反了这一规则,因为带孔的矩形不是矩形

通常,最好使用接口将行为划分为合理的可实现块。这种接口通常用形容词而不是名词来命名。例如,渲染矩形和带孔的矩形都有意义,因此接口可能是
i可渲染的
。如果它是可调整大小的,您可能会有一个
IResizable
,等等。这些可以聚合为
IShape
,但您需要注意的是,您对形状的定义只定义了问题域中的行为

直接从另一个类派生可能是危险的,因为您会受到该类行为的约束。如果您确实需要这样做,那么最好将您需要的实现提取到一个公共基类中(例如,
Rectangle:RectangleImplementation,IShape
)。

这就是为什么有先见之明的C语言设计人员在语言中添加sealed关键字的原因。明智地使用


并使用代码契约测试不变量,以获得有关破坏的早期警告。

在这些类型的情况下,更好地使用装饰模式。 这提供了更好的扩展方式

这可以使用下图来实现:


矩形对象将被创建并包装到负责提供孔的HoleCorator对象中。当矩形的大小调整完成后,将调用HoleDecorator的大小调整,这将首先调用矩形对象的大小调整,然后调用孔装饰器的AddedBehavior,它将指定在调整主组件大小时对孔所做的操作。

我认为这与c#或继承无关。无论您做什么,这都是软件开发中不可避免的问题


最好且简单的解决方案是每天构建代码并执行。

在C#中这不是需要小心的事情,在任何面向对象语言中都是需要小心的事情。基类不应该担心他们的后代。@ RabiTux:我说C,因为C++中我们可以从多个类继承,并且更容易陷入麻烦。在C#中,我们只能从一个类继承。我仍然坚持我所说的。无论使用哪种语言,都要注意这一点。这不是C#独有的。Hans,你说的“使用代码契约测试不变量以获得破坏的早期警告”是什么意思?可以指定带孔矩形的实现是什么样子的吗?我们总是使用单元测试和CI,但我不认为这在这种情况下有什么帮助。我们不会针对还不存在的情况创建单元测试。在开发之前,我们不可能有一个预期调整大小方法的单元测试。单元测试通常调用方法并比较输入和输出。我正在为类似的问题进行基于场景的单元测试。以你为榜样;创建矩形后,传递给矩形测试(执行调整大小、移动等)的对象将进行测试,并通过具有相同上下文的孔测试(执行边界检查)的矩形。这完全取决于开发人员的愿景,并不完美,但有时比方法测试更有效。顺便说一句,它并没有取代方法测试,它只是一个额外的测试。