为什么C#类默认情况下是非密封的,而它们的方法则默认为非虚拟的?

6
C#中的方法默认情况下是非虚拟的。另一个问题的这个答案解释了这样做的优点:
“类应该被设计为具有继承性,以便能够利用它。默认情况下将方法声明为虚拟意味着可以插入和替换类中的每个函数,这并不是一件好事。”
甚至Anders Hejlsberg 似乎也给出了同样的理由
“当我们在API中发布虚拟方法时,我们不仅承诺调用此方法时会发生x和y。我们还承诺在你重写此方法时,我们将按照特定的顺序调用它,并且与这些其他方法相关的状态将保持在这种不变性和那种状态......你不希望用户在API中的任何随意点上进行重写和挂钩,因为您不能保证这些承诺。”
我同意这种推理:通常,当我创建一个非私有方法时,我只想创建可从类的外部调用的代码。通常,没有考虑过别人如何覆盖此方法以及会产生怎样的影响。对于特殊情况,我可以使用virtual来表示我确实创建了一种覆盖它很有意义的代码。
但是,默认情况下类仍未封闭。默认情况下假定我会花费额外的精力来确保继承类是有意义的。 在这方面,有什么使一个类不同于方法的东西吗? 编辑 我不知道如何修改“暂停-基于观点”的事情。我从未要求过意见。也许我必须明确说明? 我不想要意见。 正确的答案将提供一个类与方法不同的示例,或者声明在这种情况下没有区别。

5
“默认虚拟”是指“默认未封闭”,对吗?“Virtual”不是我们通常用于类的形容词。 - Eric Lippert
1
为什么标题说方法默认是虚拟的,而问题的第一句话说它们默认不是虚拟的? - user47589
@Amy,现在我对术语完全感到困惑了:D谢谢你,我已经调整好了。 - Raphael Schmitz
1
“基于观点”的逻辑是,当一个问题的答案只有少数人确切知道时,这个问题往往会吸引到一些没有来源支持的观点性回答,而不是事实性回答。我不同意这种评估,更倾向于将这类问题标记为“不清楚你在问什么”,因为“为什么”和“为什么不”问题通常非常模糊。这是一个写得很好的“为什么不”问题的例子;你清楚地表达了自己的提问动机和需要的解释类型,并且你已经做了调查研究,所以感谢你的付出。 - Eric Lippert
1个回答

10

我认为问题是:“既然有很好的理由支持默认情况下方法不应该是虚拟的,为什么类不应该默认也是密封的呢?”

我们还可以补充一点:C# 使默认的可访问性为 internal(对于顶级类型)或 private(对于类型成员);也就是说,它选择更严格和更安全的选项;如果开发人员希望采用不太严格、更危险的选项,则可以选择它。默认情况下密封也将选择更严格和更安全的选项作为默认值。

此外,将一个类解除密封永远都不会造成破坏性变化,但后来决定将一个类密封起来会产生破坏性变化。因此,C#通常更喜欢鼓励减少破坏性变化的设计选择,所以出于这个原因,你会认为 C# 类应该默认为密封的。

我们已经确定了三个原因,表明按默认情况下密封是一个好主意,并与 C# 中的其他设计选择一致。那么为什么 C# 在这方面不一致呢,选择将未密封的类作为默认值?

我不知道。这一直是我认为 C# 中的一个小设计缺陷。我从来没有见过对这个选择的充分论据,也不知道它是否在早期的设计会议上进行了讨论;那是在我加入设计团队之前。

除非你遇到了参加过 2001 年设计会议的人并询问他们,否则你可能无法得到满意的答案。

我有一个习惯,就是除非我需要设计它以实现继承,否则我会将编写的每个类都标记为sealed; 我鼓励每个人也这么做。


3
如果封闭一个类是一种破坏性变更,那么现在改变默认行为将是毁灭性的。 - C.Evenhuis
1
我不得不承认我有点生气。在我花了半个多小时写这个问题后,你在不到6分钟的时间里写出了一个“更好”的版本并回答了它。 :D 不过我还是要说,这是一个很好的答案,+1 - Raphael Schmitz
2
@C.Evenhuis:没错,现在改变这种行为会带来比防止它更多的伤害。 - Eric Lippert
3
@RaphaelSchmitz 你可以阅读Eric的文章为什么许多框架类都是sealed?,文章中详细解释了什么是sealed classes。 - Trevor
4
@RaphaelSchmitz:六分钟,再加上每天八小时学习C#设计七年。我并不是有意惹你生气。 - Eric Lippert
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接