我想听听.Net框架中大量密封类背后的动机是什么。密封课程有什么好处?我无法理解如何不允许继承有用,而且很可能不是唯一一个与这些类斗争的人。
那么,为什么框架以这种方式设计并且不会是开启一切的不可破解的变化?必须有另一个原因,但只是邪恶?
答案 0 :(得分:98)
类应该设计为继承或禁止它。设计继承需要付出代价:
Effective Java的第17项详细介绍了这一点 - 无论它是在Java的上下文中编写的,这个建议也适用于.NET。
我个人希望在.NET中默认密封类。
答案 1 :(得分:40)
此主题的MSDN文章为Limiting Extensibility by Sealing Classes。
答案 2 :(得分:6)
似乎official Microsoft guidelines on sealing已经发展,因为这个问题是在9年前被问到的,并且他们从选择加入的哲学(默认为封印)转变为选择退出(不要封印默认值):
X不要在没有充分理由的情况下密封课程。
密封类因为您无法想到可扩展性方案 不是一个好理由。框架用户喜欢从类继承 各种非显而易见的原因,如添加便利成员。看到 未密封的类,用于用户想要的非显而易见的原因 从类型继承。
密封课程的充分理由包括:
- 该类是一个静态类。请参阅静态类设计。
- 该类在继承的受保护成员中存储安全敏感的机密。
- 该类继承了许多虚拟成员以及密封它们的成本 单独会超过离开课程的好处 启封。
- 该类是一个需要非常快的运行时的属性 抬头。密封属性具有稍高的性能水平 比未密封的。参见属性。
X不要在密封类型上声明受保护或虚拟成员。
根据定义,密封类型不能继承。这意味着 无法调用密封类型上的受保护成员和虚拟成员 密封类型的方法不能被覆盖。
✓考虑您覆盖的密封成员。引入虚拟成员可能导致的问题(在虚拟成员中讨论) 同样适用于覆盖,尽管程度稍低。 密封覆盖可以保护您免受这些问题的影响 指向继承层次结构。
的确,如果你search the ASP.Net Core codebase,你只会发现大约30个sealed class
,其中大部分是属性和测试类。
我认为不变性保护是支持密封的好理由。
答案 3 :(得分:4)
我在msdn文档中发现了这句话:“密封类主要用于防止派生。因为它们永远不能用作基类,所以一些运行时优化可以使调用密封类成员的速度稍快。”
我不知道表演是否是密封课程的唯一优势,而且我个人也想知道任何其他原因......
答案 4 :(得分:3)
性能是一个重要因素,例如,java中的字符串类是final(< - sealed),其原因仅在于性能。 我认为另一个重点是避免这里详细描述的脆弱的基类问题: http://blogs.msdn.com/ericlippert/archive/2004/01/07/virtual-methods-and-brittle-base-classes.aspx
如果您提供框架,那么对于可维护性遗留项目以及升级框架以避免脆弱的基类问题非常重要
答案 5 :(得分:1)
密封用于防止“脆弱的基类问题”。我在MSDN中找到了good article来解释这一点。
答案 6 :(得分:0)
密封可以让您实现一些轻微的性能提升。在JITs和懒惰的悲观世界中,这比在C ++世界中更少,但由于.NET不像悲观化那样好,因为java编译器主要是因为不同的设计理念,它仍然是有用的。它告诉编译器它可以直接调用任何虚拟方法,而不是通过vtable间接调用它们。
当你想要平等比较之类的“封闭世界”时,这一点也很重要。通常,一旦我定义了一个虚拟方法,我就会非常谨慎地定义一个真正实现这个想法的相等比较概念。另一方面,我可能能够使用virtual方法为类的特定子类定义它。密封该类可确保平等确实存在。
答案 7 :(得分:0)
密封课程可以更轻松地管理一次性资源。
答案 8 :(得分:0)
要确定是否要密封班级,方法或财产,通常应考虑以下两点:
•通过定制课程的能力可以获得课程的潜在好处。
•派生类的潜力可以修改您的类,使其不再正常工作或按预期工作。
答案 9 :(得分:0)
进一步的考虑是密封的类不能在单元测试中存根。来自Microsoft's documentation:
无法对存根类或静态方法进行存根,因为存根类型依赖于虚方法调度。对于此类情况,请使用填充类型,如使用填充程序将应用程序与其他程序集隔离以进行单元测试
中所述