.net 为什么要封类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/268251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:31:41  来源:igfitidea点击:

Why seal a class?

.netperformance

提问by mmiika

I'd like to hear what is the motivation behind the bulk of sealed classes in the .Net framework. What is the benefit of sealing a class? I cannot fathom how not allowing inheritance can be useful and most likely not the only one fighting these classes.

我想听听 .Net 框架中大量密封类背后的动机是什么。封类有什么好处?我无法理解不允许继承是如何有用的,而且很可能不是唯一一个与这些类作斗争的人。

So, why is the framework designed this way and wouldn't it be unbreaking change to unseal everything? There must be another reason but just being evil?

那么,为什么框架是这样设计的,并且解开一切难道不是一个不间断的变化吗?除了邪恶之外,一定还有其他原因吗?

采纳答案by CVertex

  • Sometimes classes are too precious and not designed to be inherited.
  • Runtime/Reflection can make inheritance assumptions about sealed classes when looking for types. A great example of this is - Attributes are recommended to be sealed for lookup runtime speed. type.GetCustomAttributes(typeof(MyAttribute)) will perform significantly faster if MyAttribute is sealed.
  • 有时类太宝贵了,而不是为了继承而设计的。
  • 运行时/反射可以在查找类型时对密封类进行继承假设。一个很好的例子是 - 建议密封属性以提高查找运行时的速度。如果 MyAttribute 被密封,type.GetCustomAttributes(typeof(MyAttribute)) 的执行速度会明显加快。

The MSDN article for this topic is Limiting Extensibility by Sealing Classes.

此主题的 MSDN 文章是通过密封类限制可扩展性

回答by Jon Skeet

Classes should either be designed for inheritance or prohibit it. There is a cost to designing for inheritance:

类应该被设计为继承或禁止继承。设计继承是有代价的:

  • It can pin down your implementation (you have to declare which methods are going to call which other methods, in case a user overrides one but not the other)
  • It reveals your implementation rather than just the effects
  • It means you have to think of more possibilities when designing
  • Things like Equals are hard to design in an inheritance tree
  • It requires more documentation
  • An immutable type which is subclassed may become mutable (ick)
  • 它可以确定您的实现(您必须声明哪些方法将调用哪些其他方法,以防用户覆​​盖一个而不是另一个)
  • 它揭示了您的实施,而不仅仅是效果
  • 这意味着你在设计时要考虑更多的可能性
  • 像 Equals 这样的东西很难在继承树中设计
  • 它需要更多的文档
  • 子类化的不可变类型可能会变得可变(ick)

Item 17 of Effective Java goes into more details on this - regardless of the fact that it's written in the context of Java, the advice applies to .NET as well.

Effective Java 的第 17 条更详细地介绍了这一点 - 不管它是在 Java 上下文中编写的,该建议也适用于 .NET。

Personally I wish classes were sealed by default in .NET.

我个人希望默认情况下在 .NET 中密封类。

回答by Ohad Schneider

It seems that the official Microsoft guidelines on sealinghave evolved since this question was asked ~9 years ago, and they moved from an opt-in philosophy (seal by default) to opt-out (don't seal by default):

自从大约 9 年前提出这个问题以来,微软关于密封官方指南似乎已经发生了变化,并且他们从选择加入哲学(默认情况下密封)转变为选择退出(默认情况下不密封):

X DO NOTseal classes without having a good reason to do so.

Sealing a class because you cannot think of an extensibility scenario is not a good reason. Framework users like to inherit from classes for various nonobvious reasons, like adding convenience members. See Unsealed Classes for examples of nonobvious reasons users want to inherit from a type.

Good reasons for sealing a class include the following:

  • The class is a static class. See Static Class Design.
  • The class stores security-sensitive secrets in inherited protected members.
  • The class inherits many virtual members and the cost of sealing them individually would outweigh the benefits of leaving the class unsealed.
  • The class is an attribute that requires very fast runtime look-up. Sealed attributes have slightly higher performance levels than unsealed ones. See Attributes.

X DO NOTdeclare protected or virtual members on sealed types.

By definition, sealed types cannot be inherited from. This means that protected members on sealed types cannot be called, and virtual methods on sealed types cannot be overridden.

? CONSIDERsealing members that you override. Problems that can result from introducing virtual members (discussed in Virtual Members) apply to overrides as well, although to a slightly lesser degree. Sealing an override shields you from these problems starting from that point in the inheritance hierarchy.

X 不要在没有充分理由的情况下密封类。

因为无法想到可扩展性场景而密封类并不是一个很好的理由。框架用户出于各种不明显的原因喜欢从类继承,比如添加方便的成员。有关用户想要从类型继承的非明显原因的示例,请参阅未密封的类。

密封类的充分理由包括:

  • 该类是静态类。请参见静态类设计。
  • 该类将安全敏感的机密存储在继承的受保护成员中。
  • 该类继承了许多虚拟成员,单独密封它们的成本将超过不密封该类的好处。
  • 类是一个需要非常快速的运行时查找的属性。密封属性的性能水平略高于非密封属性。请参阅属性。

X 不要在密封类型上声明受保护或虚拟成员。

根据定义,密封类型不能被继承。这意味着无法调用密封类型上的受保护成员,并且无法覆盖密封类型上的虚拟方法。

? 考虑您覆盖的密封成员。引入虚拟成员(在虚拟成员中讨论)可能导致的问题也适用于覆盖,尽管程度稍低。从继承层次结构中的那个点开始,密封覆盖可以保护您免受这些问题的影响。

Indeed, if you search the ASP.Net Core codebase, you will only find about 30 occurences of sealed class, most of which are attributes and test classes.

事实上,如果你搜索 ASP.Net Core 代码库,你只会发现大约 30 次出现sealed class,其中大部分是属性和测试类。

I do think that immutability conservation is a good argument in favor of sealing.

我确实认为不变性守恒是支持密封的一个很好的论据。

回答by bruno conde

I found this sentence in msdn documentation: "Sealed classes are primarily used to prevent derivation. Because they can never be used as a base class, some run-time optimizations can make calling sealed class members slightly faster."

我在 msdn 文档中找到了这句话:“密封类主要用于防止派生。因为它们永远不能用作基类,因此一些运行时优化可以使调用密封类成员的速度稍微快一些。”

I don't know if the performance is the only advantage of sealed classes and personally I also would like to know any other reasons ...

我不知道性能是否是密封类的唯一优势,我个人也想知道任何其他原因......

回答by Peter Parker

Performance is an important factor for example, the string class in java is final(<- sealed) and reason for this is performance only. I think another important point is to avoid the brittle base class problem described in detail here: http://blogs.msdn.com/ericlippert/archive/2004/01/07/virtual-methods-and-brittle-base-classes.aspx

性能是一个重要因素,例如,java 中的字符串类是最终的(<- 密封),其原因仅在于性能。我认为另一个重点是避免这里详细描述的脆弱基类问题:http: //blogs.msdn.com/ericlippert/archive/2004/01/07/virtual-methods-and-brittle-base-classes。 aspx

If you provide a framework it is important for maintainability legacy projects and to upgrade your framework to avoid the brittle base class problem

如果你提供了一个框架,那么对于遗留项目的可维护性和升级你的框架以避免脆弱的基类问题很重要

回答by ihebiheb

Sealed is used to prevent the "brittle base class problem". I found a good articlein MSDN that explains that.

Sealed 用于防止“脆弱的基类问题”。我在 MSDN 上找到了一篇很好的文章来解释这一点。

回答by Jeff Dunlop

Sealing a class makes managing disposable resources easier.

密封一个类使管理一次性资源更容易。

回答by user3629577

To determine whether to seal a class, method, or property, you should generally consider the following two points:

确定是否对类、方法或属性进行密封,一般应考虑以下两点:

?The potential benefits that deriving classes might gain through the ability to customize your class.

? 派生类可能通过自定义类的能力获得的潜在好处。

?The potential that deriving classes could modify your classes in such a way that they would no longer work correctly or as expected.

? 派生类可能会修改您的类,使其不再正常或按预期工作。

回答by Dave Clark

A further consideration is that sealed classes can't be stubbed in your unit tests. From Microsoft's documentation:

另一个考虑是密封类不能在您的单元测试中存根。来自微软的文档

Sealed classes or static methods can't be stubbed because stub types rely on virtual method dispatch. For such cases, use shim types as described in Using shims to isolate your application from other assemblies for unit testing

密封类或静态方法不能被存根,因为存根类型依赖于虚拟方法分派。对于这种情况,请按照使用垫片将应用程序与其他程序集隔离以进行单元测试中所述使用垫片类型

回答by Edward KMETT

Sealing allows you to realize some minor performance gains. This is less true in the world of JITs and lazy pessimization than in the world of, say C++, but since .NET is not as good as pessimization as java compilers are mostly because of different design philosophies it is still useful. It tells the compiler that it can directly call any virtual methods rather than call them indirectly through the vtable.

密封允许您实现一些小的性能提升。这在 JIT 和惰性悲观世界中不如在 C++ 世界中那么真实,但由于 .NET 不如 Java 编译器那样悲观,主要是因为不同的设计理念,它仍然有用。它告诉编译器它可以直接调用任何虚方法,而不是通过 vtable 间接调用它们。

It is also important when you want a 'closed world' for things like equality comparison. Normally once I define a virtual method, I'm pretty much hosed for defining a notion of equality comparison that really implements the idea. On the other hand, I might be able to define it for a particular subclass of the class with the virtual method. Sealing that class ensures that equality really does hold.

当您想要一个“封闭的世界”来进行平等比较时,这也很重要。通常,一旦我定义了一个虚拟方法,我就会非常难以定义一个真正实现这个想法的相等比较的概念。另一方面,我也许可以使用虚方法为类的特定子类定义它。密封该类可确保平等确实成立。