我想知道.Net框架中大量使用密封类的动机是什么。密封类的好处是什么?我无法理解不允许继承可能有什么用处,我也不是唯一反对这些类的人。
那么,为什么框架被设计成这样,解密所有类是否会破坏性变化?肯定有其他原因而不是只是出于恶意吧?
我想知道.Net框架中大量使用密封类的动机是什么。密封类的好处是什么?我无法理解不允许继承可能有什么用处,我也不是唯一反对这些类的人。
那么,为什么框架被设计成这样,解密所有类是否会破坏性变化?肯定有其他原因而不是只是出于恶意吧?
类应该设计为可继承或禁止继承。设计用于继承会有成本:
Effective Java 的第17条详细讨论了这个问题 - 尽管它是针对 Java 写的,但建议同样适用于 .NET。
个人认为在 .NET 中默认应该封闭类。
该主题的MSDN文章为通过密封类限制可扩展性。
不要没有充分理由就对类进行封装。
仅仅因为你想不到扩展性场景而去封装一个类是不足以成为一个好理由的。框架用户喜欢从各种非显而易见的原因中继承类,例如添加方便成员。请参阅未封装类的示例,了解用户希望从类型继承的非显而易见的原因。
封装一个类的好理由包括以下几点:
- 该类是静态类。请参阅静态类设计。
- 该类在继承的受保护成员中存储安全敏感密钥。
- 该类继承了许多虚函数,并且单独封装这些函数的成本会超过让该类保持未封装状态的好处。
- 该类是需要非常快速的运行时查找的属性。封装的属性比未封装的属性具有稍高的性能水平。请参阅属性。
不要在封装类型上声明受保护或虚函数成员。
按定义,封装类型无法被继承。这意味着无法调用封装类型上的受保护成员,也无法覆盖封装类型上的虚函数。
✓ 考虑封装你重写的成员。引入虚拟成员可能会导致一些问题(如虚拟成员中所述),尽管影响稍微小了一点,但对重写同样适用。对重写进行封装可以从继承层次结构的那一点开始避免这些问题。
的确,如果你搜索ASP.Net Core代码库,你只会找到大约30个sealed class
的出现,其中大部分是属性和测试类。
我认为保持不可变性是支持封装的好理由。
我在MSDN文档中发现了这句话:"Sealed类主要用于防止派生。因为它们永远不能用作基类,一些运行时优化可以使调用sealed类成员稍微快一些。"
我不知道性能是否是sealed类的唯一优点,个人也想知道其他原因...
String
类可能也无法被子类化。 - wcharginSealed用于防止“脆弱基类问题”。我在MSDN上找到了一篇好文章来解释这个问题。
将类封装起来可以更轻松地管理可释放资源。
密封允许您实现一些轻微的性能提升。在JIT和懒惰的pessimization世界中,这种情况不太真实,而在C++等领域中则更为真实,但由于.NET不像Java编译器那样擅长pessimization,主要是因为不同的设计哲学,因此仍然很有用。它告诉编译器它可以直接调用任何虚拟方法,而不是通过vtable间接调用它们。
当您想要一个“封闭的世界”用于诸如相等比较之类的事物时,这也很重要。通常,一旦我定义了一个虚拟方法,我就几乎无法定义真正实现该想法的相等比较概念。另一方面,我可能能够为具有虚拟方法的类的特定子类定义它。密封该类可确保相等性确实成立。
由于存根类型依赖于虚方法分派,因此无法对密封类或静态方法进行存根。对于这种情况,请使用Shim类型,如在使用Shim类型隔离应用程序与其他程序集进行单元测试中所述。
为确定是否封装一个类、方法或属性,通常应考虑以下两点:
•派生类通过自定义您的类可能获得的潜在好处。
•派生类修改您的类的潜力,使其不能正确地工作或按预期工作。