在Java中,您可以将method标记为final,以使其无法覆盖。
在C#中,您必须将方法标记为虚拟方法,以使其能够被覆盖。
这是否意味着在C#中,您应该将所有方法标记为虚拟方法(除了一些您不想被覆盖的方法之外),因为您很可能不知道可以通过什么方式继承您的类?
在Java中,您可以将method标记为final,以使其无法覆盖。
在C#中,您必须将方法标记为虚拟方法,以使其能够被覆盖。
这是否意味着在C#中,您应该将所有方法标记为虚拟方法(除了一些您不想被覆盖的方法之外),因为您很可能不知道可以通过什么方式继承您的类?
final
字段,我知道他在谈论字段。但是我认为他也谈到了有效Java中的最终方法。但是,我可能会忘记这一点。我可以确定,他可能会在其他演讲中提到它。
Answers:
在C#中,您必须将方法标记为虚方法,以使其能够被覆盖。这是否意味着在C#中,您应该将所有方法标记为虚拟方法(除了一些您不想被覆盖的方法之外),因为您很可能不知道可以通过什么方式继承您的类?
否。如果语言设计人员认为virtual应该是默认值,那么它将是默认值。
可覆盖性是一种功能,与所有功能一样,它具有成本。可重写方法的成本是巨大的:设计,实现和测试成本很高,尤其是对类有“敏感性”时;虚拟方法是将未经测试的第三方代码引入系统的方式,并且具有安全性。
如果您不知道如何继承您的类,请不要发布您的类,因为您尚未完成对它的设计。您的扩展性模型绝对是您应该提前知道的;它会深刻影响您的设计和测试策略。
我主张所有类都是密封的,并且所有方法都是非虚拟的,直到您有一个以客户为中心的真实世界的理由来解封或将方法虚拟化。
基本上,您的问题是“我不知道我的客户打算如何消费我的课程;因此我应该使它可以任意扩展吗?” 没有; 你应该变得博学多才!您不会问“我不知道我的客户将如何使用我的类,所以我应该将我的所有属性都读写吗?并且应该让我的所有方法都将委托类型的属性读写给我,以便我的用户可以用自己的实现替换任何方法吗?” 不,在您有证据证明用户确实需要该功能之前,请勿执行任何此类操作!花费宝贵的时间来设计,测试和实现用户真正想要和需要的功能,并且从知识的角度去做。
sealed
默认为类,而不是默认类,我觉得很有趣。
在我看来,当前接受的答案是不必要的教条主义。
事实是,当您未将方法标记为时virtual
,其他人将无法覆盖其行为,并且当您将类标记为sealed
其他人无法从该类继承时。这会引起严重的疼痛。我不知道我诅咒一个API来标记类sealed
或不标记方法的次数virtual
仅仅是因为他们没有预料到我的用例。
从理论上讲,这可能是正确的方法,只允许重写和继承要被重写和继承的类,但实际上,不可能预见所有可能的情况,因此确实没有充分的理由将其封闭。
sealed
。virtual
。进行调用的一种方法是查看方法或属性的名称。一对GetLength()在列表的方法不正是顾名思义,它不允许太多的解释。更改其实现可能不是很透明,因此将其标记为virtual
不必要的。将Add
方法标记为虚拟方法更为有用,因为有人可以创建一个特殊的列表,该列表仅通过Add方法等接受某些对象。另一个示例是自定义控件。您可能希望使用主要的绘制方法,virtual
以便其他人可以使用大部分行为并仅更改外观,但您可能不会覆盖X和Y属性。
最后,您通常不必立即做出决定。在内部项目中,无论如何您都可以轻松更改代码,我不会担心这些事情。如果需要重写某个方法,则总是可以在发生这种情况时将其设为虚拟。相反,如果项目是别人使用的API或库,并且更新缓慢,那么考虑哪些类和方法可能是有用的,那肯定是值得的。在这种情况下,我认为最好是开放而不是严格关闭。
否。只有要让派生类指定的方法才应该是虚拟的。
虚拟与最终无关。
为了防止在C#中覆盖虚拟方法,请使用 sealed
public class MyClass
{
public sealed override void MyFinalMethod() {...}
}
final
的方式表示not virtual
。
是的你应该。我希望回答的答案与大多数其他答案不同。这是C#中的缺陷。缺陷。设计错误。与Java相比,您可以看到所有方法都是“虚拟”的,除非另有说明(“最终”)。当然,如果存在带有“区域”方法的“矩形”类,并且您希望有自己的类以边距表示“矩形”。您希望利用现有类的所有属性和方法,并且只想添加一个“ margin”属性,为常规矩形区域添加一些值,并且如果Rectangle中的area方法未标记为virtual,你注定了。图片,请使用矩形数组并返回所有矩形的面积之和的方法。有些可以是规则的矩形,有些可以带有边距。现在,读回标记为“正确”的答案,描述“安全问题”或“测试”。与无能力超越相比,这些毫无意义。
别人回答“不”,我并不感到惊讶。我很惊讶C#的作者在将语言基于Java时看不到它。
将方法虚拟化通常会减慢需要调用它的所有代码。这种减慢将是微不足道的,但在某些情况下可能会很大(除其他外,因为可以内联非虚拟方法调用,这又可以使优化程序消除不必要的操作)。并非总是能够预测虚拟调用可能影响执行速度的程度,通常应该使做一些会使代码变慢的事情无效,除非这样做有明显的好处。
在许多情况下,使方法成为非虚拟方法的性能好处可能足以证明默认情况下方法为非虚拟方法,但是当将类设计为继承时,大多数方法应该是虚拟的且未密封。非虚拟或密封方法的主要用途应该是其他(可能受保护的)虚拟方法的包装器(要更改基础行为的代码应覆盖适当的虚拟方法,而不是包装器)。
将类标记为sealed
或将继承限制为程序集中其他类的原因常常与性能无关。其中,如果一个类是可外部继承的,则具有protected
作用域的所有成员都会有效地添加到其公共API中,并且其在基类中的行为的任何更改都可能破坏依赖该行为的任何派生类。另一方面,如果一个类是可继承的,则使用其方法virtual
并不会真正增加其暴露程度。如果有的话,它可以通过允许派生类完全“掩埋”与派生类不再相关的基类实现方面来减少派生类对基类内部的依赖(例如,如果List<T>
如果是虚拟的,则覆盖它们的派生类可以使用数组数组来保存事物(避免大对象堆问题),而不必尝试使使用的私有数组List<T>
与数组保持一致。数组。
不,您不应将所有方法都标记为虚拟方法。您应该考虑如何继承您的类。如果不应继承该类,则将其标记为密封,并且显然成员不应为虚拟成员。如果您的类很可能会被继承,则您确实应该最大限度地提高覆盖行为的能力。因此,除非有理由不要在此类中的任何地方大范围使用虚拟。