我应该将所有方法都标记为虚拟吗?

2022-08-31 13:24:38

在Java中,您可以将方法标记为最终版本,使其无法重写。

在 C# 中,必须将方法标记为虚拟方法,以便能够重写。

这是否意味着在 C# 中,您应该将所有方法标记为虚拟(除了一些您不想被覆盖的方法),因为很可能您不知道您的类可以以何种方式继承?


答案 1

在 C# 中,必须将方法标记为虚拟方法,以便能够重写。这是否意味着在 C# 中,您应该将所有方法标记为虚拟(除了一些您不想被覆盖的方法),因为很可能您不知道您的类可以以何种方式继承?

不。如果语言设计人员认为虚拟应该是默认的,那么它就是默认的

可覆盖性是一种功能,与所有功能一样,它也有成本。可重写方法的成本相当可观:有很大的设计,实现和测试成本,特别是如果对类有任何“敏感性”;虚拟方法是将未经测试的第三方代码引入系统并具有安全影响的方法。

如果您不知道打算如何继承您的类,那么请不要发布您的类,因为您尚未完成设计。您的可扩展性模型绝对是您应该提前了解的内容;它应该会深刻影响您的设计和测试策略。

我主张所有类都是密封的,所有方法都是非虚拟的,直到你有一个以现实世界为中心的以客户为中心的理由来解封或使方法虚拟。

基本上你的问题是“我不知道我的客户打算如何消费我的课程;因此,我应该让它任意扩展吗?否;你应该变得知识渊博!你不会问“我不知道我的客户将如何使用我的类,所以我应该让我的所有属性都读写吗?我是否应该使我的所有方法都读写为委托类型的属性,以便我的用户可以用自己的实现替换任何方法?不,在你有证据表明用户确实需要这种能力之前,不要做任何这些事情!将宝贵的时间花在设计、测试和实现用户实际想要和需要的功能上,并从知识的角度出发。


答案 2

在我看来,目前接受的答案是不必要的教条主义。

事实是,当您不将方法标记为 时,其他方法不能覆盖其行为,并且当您将类标记为其他方法无法从该类继承时。这可能会导致剧烈的疼痛。我不知道有多少次我诅咒API用于标记类或不标记方法,仅仅是因为他们没有预料到我的用例。virtualsealedsealedvirtual

从理论上讲,只允许重写方法和继承旨在被覆盖和继承的类可能是正确的方法,但在实践中,不可能预见到每种可能的场景,并且真的没有充分的理由如此封闭。

  1. 如果您没有很好的理由,请不要将类标记为 .sealed
  2. 如果你的库是要被其他人使用的,那么至少尝试将包含该行为的类的主要方法标记为.virtual

进行调用的一种方法是查看方法或属性的名称。List 上的 GetLength() 方法完全符合名称的含义,并且不允许进行太多解释。更改其实现可能不是很透明,因此将其标记为可能没有必要。将该方法标记为虚拟要有用得多,因为有人可以创建一个特殊的列表,该列表仅通过Add方法等接受某些对象。另一个示例是自定义控件。您可能希望制作主绘制方法,以便其他人可以使用大部分行为并更改外观,但您可能不会覆盖 X 和 Y 属性。virtualAddvirtual

最后,您通常不必立即做出决定。在一个内部项目中,你可以很容易地改变代码,无论如何,我不会担心这些事情。如果需要重写某个方法,则始终可以在发生这种情况时将其设置为虚拟方法。相反,如果项目是一个被其他人使用并且更新缓慢的API或库,那么考虑哪些类和方法可能是有用的当然是值得的。在这种情况下,我认为最好是开放而不是严格封闭。