我应该标记所有方法虚拟?

在Java中,您可以将方法标记为final,以使其不可覆盖。

在C#中,您必须将方法标记为虚拟以使其可以覆盖。

这是否意味着在C#中你应该标记所有的方法是虚拟的(除了几个你不想被覆盖的方法),因为你很可能不知道你的类可以被inheritance的方式?

在C#中,您必须将方法标记为虚拟以使其可以覆盖。 这是否意味着在C#中你应该标记所有的方法是虚拟的(除了几个你不想被覆盖的方法),因为你很可能不知道你的类可以被inheritance的方式?

不。如果语言devise者认为虚拟应该是默认的,那么这将是默认设置

Overridablility是一个function ,就像所有的function一样,它有成本 。 一个可重写的方法的成本是相当可观的:有大的devise,实施和testing成本,特别是如果对class级有任何“敏感” 虚拟方法是将未经testing的第三方代码引入到系统中并具有安全影响的方法。

如果你不知道你打算如何inheritance你的课程,那么不要发布你的课程,因为你还没有完成devise。 你的可扩展性模型绝对是你应该提前知道的东西; 它应该深深地影响你的devise和testing策略。

我主张所有的课程都是封闭的 ,所有的方法都是非虚拟的,直到你有一个真实的以客户为中心的理由去开封或者使一个方法变成虚拟的。

基本上你的问题是“我不知道我的客户打算如何消费我的课程,因此我应该把它做成任意可扩展的? 没有; 你应该变得知识渊博 ! 你不会问“我不知道我的客户如何使用我的类,所以我应该使我所有的属性读写吗?我应该使我所有的方法读写属性的委托types,使我的用户可以用自己的实现来replace任何方法吗?“ 不,在你有证据表明用户确实需要这些function之前,不要做任何这些事情! 花费宝贵的时间来devise,testing和实现用户真正想要和需要的function,并从知识位置这样做。

没有! 因为你不知道你的类是如何被inheritance的,所以如果你知道你想让它被覆盖的话,你应该标记一个方法。

我认为目前接受的答案是不必要的教条。

事实是,当你不把方法标记为virtual ,别人不能重写它的行为,当你将一个类标记为sealed别人不能从类inheritance。 这会造成很大的痛苦。 我不知道有多less次我诅咒标记类sealed或不标记方法virtual只是因为他们没有预料到我的使用情况。

从理论上讲,可能是正确的方法,只允许覆盖方法和inheritance的类被覆盖和inheritance,但实际上是不可能预见到每一个可能的情况,真的没有一个很好的理由被closures。

  1. 如果你没有很好的理由,那么不要把课程标为sealed
  2. 如果你的图书馆是为了被别人消费的话,那么至less要把一个包含行为的类的主要方法标记为virtual

打电话的一种方法是查看方法或属性的名称。 List上的GetLength()方法正是名字所暗示的,并且不允许有太多的解释 。 改变它的实现可能不是很透明,所以将其标记为virtual可能是不必要的。 将Add方法标记为虚拟是非常有用的,因为有人可以通过Add方法创build一个特殊的List来接受一些对象。另一个例子是自定义控件。 你会想让主绘图方法是virtual以便其他人可以使用大部分的行为,只是改变外观,但你可能不会重写X和Y属性。

最后,你通常不必马上做出这个决定。 在一个内部项目中,无论如何您都可以轻松更改代码,我不担心这些事情。 如果一个方法需要被覆盖,那么当这种情况发生的时候,你总是可以把它变成虚拟的。 相反,如果这个项目是一个被别人使用并且更新速度慢的API或者库,那么肯定会想到哪些类和方法可能是有用的。 在这种情况下,我认为最好是开放而不是严格closures。

不可以。只有您希望派生类指定的方法应该是虚拟的。

虚拟与final没有关系。

为了防止在C#中覆盖虚拟方法,请使用sealed

 public class MyClass { public sealed override void MyFinalMethod() {...} } 

我们可以想出两个阵营的理由,但这完全没用。

在Java中有数以百万计的意外的非最终公共方法,但我们听到很less的恐怖故事。

在C#中有数以百万计的公开方法,我们听到很less的恐怖故事。

所以这不是一个大问题 – 重写公共方法的必要性很less,因此无论如何也没有意义。


这让我想起另一个论点 – 一个局部variables是否应该是最终的默认值。 这是个不错的主意,但我们不能夸大它的价值。 有几十亿的局部variables可能是但不是最终的,但已经certificate这是一个实际的问题。

使虚拟方法通常会减慢任何需要调用它的代码。 这种放缓将是微不足道的,但在某些情况下可能会相当大(其中,因为可能会插入非虚方法调用,这可能反过来允许优化器消除不必要的操作)。 预测虚拟调用可能影响执行速度的程度并不总是可能的,人们通常应该做出使代码变得更慢的事情,除非这样做有明显的好处。

在许多情况下,使方法成为非虚拟的性能好处可能足以certificate缺省情况下方法是非虚拟的,但是当类被devise为被inheritance时,大多数方法应该是虚拟的并且是非封装的; 非虚拟或密封方法的主要用途应该是作为其他(可能受保护的)虚拟方法(希望改变基本行为的代码应该覆盖适当的虚拟而不是包装)的包装。

常常有非性能相关的原因,将类标记为sealed或限制对程序集中其他类的inheritance。 除此之外,如果一个类是外部可inheritance的,那么所有具有protected范围的成员都将被有效地添加到其公共API中,并且对其在基类中行为的任何更改都可能会破坏依赖于该行为的任何派生类。 另一方面,如果一个阶级是可inheritance的,那么使它的方法virtual并不能真正增加它的暴露。 如果有的话,它可以减less派生类对基类内部的依赖,允许它们完全“掩盖”派生类中不再相关的基类实现方面[例如,如果List<T>的成员是虚拟的,一个派生类覆盖它们都可以使用一个数组数组来保存东西(避免大对象堆问题),并且不必保持List<T>使用的私有数组与数组一致-arrays。