在C#和C++/CLI中,关键字sealed(或VB中的NotInheritable)用于保护类免受任何继承机会(类将是不可继承的)。我知道面向对象编程的一个特性是继承,我觉得sealed的使用违背了这个特性,它停止了继承。有没有一个例子来说明sealed的好处以及什么时候使用它很重要?
sealed
NotInheritable
bxfogqkk1#
1.在实现安全功能的类上,这样原始对象就不能被“模拟”。1.更一般地说,我最近与微软的一位人士进行了交流,他告诉我,他们试图将继承限制在真正有意义的地方,因为如果不加以处理,它会在性能方面变得昂贵。sealed关键字告诉CLR没有类可以向下查找方法,这样可以加快速度。在当今市场上的大多数性能增强工具中,您会发现一个复选框,该复选框将密封所有未继承的类。但是要小心,因为如果您希望允许通过MEF发现插件或程序集,您将遇到问题。
ylamdve62#
Louis Kottmann's excellent answer的补充:1.如果一个类不是为继承而设计的,子类可能会破坏class invariants。当然,这只适用于你创建一个公共API的情况,但是根据我的经验,我会密封任何没有显式设计为子类的类。在相关说明中,仅适用于未密封类:创建virtual的任何方法都是扩展点,或者至少看起来应该是扩展点。声明方法virtual也应该是有意识的决定。(在C#中这是有意识的决定;在Java中,它不是。)还有这个1.密封会使单元测试更加困难,因为它禁止模拟。一些相关链接:
virtual
还要注意,默认情况下Kotlin密封类;它的open关键字与Java的final或C#的sealed相反(可以肯定的是,there is no universal agreement that this is a good thing)。
open
final
aemubtdh3#
将类标记为Sealed可以防止篡改重要的类,以免危及安全性或影响性能。很多时候,当设计一个具有固定行为的实用程序类时,密封类也是有意义的,我们不想改变它。例如,C#中的System命名空间提供了许多密封的类,如String。如果不密封,则可以扩展其功能,这可能是不可取的,因为它是具有给定功能的基本类型。类似地,C#中的structures总是隐式密封的。因此,不能从另一个结构中派生一个结构/类。其原因是structures仅用于建模独立的,原子的,用户定义的数据类型,我们不想修改这些数据类型。有时候,当您构建类层次结构时,您可能希望根据您的域模型或业务规则来限制继承链中的某个分支。例如,Manager和PartTimeEmployee都是Employee,但您在组织中的兼职员工之后没有任何角色。在这种情况下,您可能需要密封PartTimeEmployee以防止进一步的分支。另一方面,如果您有小时或周兼职员工,则从PartTimeEmployee继承它们可能是有意义的。
Sealed
C#
System
String
structures
Manager
PartTimeEmployee
Employee
kh212irz4#
我认为这篇文章有一些好的观点,具体的情况是当试图将一个非密封类转换为任何随机接口时,编译器不会抛出错误;但是当使用sealed的时候编译器会抛出它不能转换的错误。Sealed类带来了额外的代码访问安全性。https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla
5kgi1eie5#
密封是一个有意识的决定,只有当你想清楚地揭示你的类的结构特征时才应该考虑。它是关于你的对象模型的结构选择。它永远不应该是关于性能或安全性()的决定。但更重要的是,永远不应该是关于对你的继承树的任意限制。我提出这个经验法则:* 如果你不得不考虑密封一个类是否是一个好主意,那么永远不应该密封它。密封一个类的决定对你来说应该是显而易见的,甚至在你编写该类的第一行代码之前就已经做出了。*举个例子,因为我们不能从它们派生,但是它们看起来很像一个普通的类,我们通常认为结构体是密封的类。这就是它们。正是这种限制允许它们实现值类型语义,因为继承和多态只能与引用类型一起工作。所以“结构体类”是密封的,因为任何实现值类型的类-类型语义必须给予继承,并以不同的方式管理其内存。(注意,这适用于C#中的任何值类型对象,而不仅仅是结构)。另一个例子:代码生成器可以编写表示窗口及其所有元素的密封类,以供用户定义其行为,因为UI引擎期望这个类而不是其他类,以便能够呈现窗口。最后一个例子:一个数学工具类可能是密封的,因为它是围绕真理构建的,任何扩展的行为都不可能是正确的或“按预期工作”。这是一个不完全属于上述经验法则的例子。永远不要盲目相信经验法则。()如果性能是应用程序中的一个问题,那么可以确定未密封的类不是原因。同样,如果依赖密封类来强制应用程序中的安全性,那么问题一定出在基类上--它们公开了什么或允许扩展什么。
6qqygrtg6#
如果你的设计模式是使用单例,你会希望密封类,这样只能创建一个示例。基本上,密封类,创建一个私有构造函数,和公共静态方法来返回类。
6条答案
按热度按时间bxfogqkk1#
1.在实现安全功能的类上,这样原始对象就不能被“模拟”。
1.更一般地说,我最近与微软的一位人士进行了交流,他告诉我,他们试图将继承限制在真正有意义的地方,因为如果不加以处理,它会在性能方面变得昂贵。
sealed关键字告诉CLR没有类可以向下查找方法,这样可以加快速度。
在当今市场上的大多数性能增强工具中,您会发现一个复选框,该复选框将密封所有未继承的类。
但是要小心,因为如果您希望允许通过MEF发现插件或程序集,您将遇到问题。
ylamdve62#
Louis Kottmann's excellent answer的补充:
1.如果一个类不是为继承而设计的,子类可能会破坏class invariants。当然,这只适用于你创建一个公共API的情况,但是根据我的经验,我会密封任何没有显式设计为子类的类。
在相关说明中,仅适用于未密封类:创建
virtual
的任何方法都是扩展点,或者至少看起来应该是扩展点。声明方法virtual
也应该是有意识的决定。(在C#中这是有意识的决定;在Java中,它不是。)还有这个
1.密封会使单元测试更加困难,因为它禁止模拟。
一些相关链接:
还要注意,默认情况下Kotlin密封类;它的
open
关键字与Java的final
或C#的sealed
相反(可以肯定的是,there is no universal agreement that this is a good thing)。aemubtdh3#
将类标记为
Sealed
可以防止篡改重要的类,以免危及安全性或影响性能。很多时候,当设计一个具有固定行为的实用程序类时,密封类也是有意义的,我们不想改变它。
例如,
C#
中的System
命名空间提供了许多密封的类,如String
。如果不密封,则可以扩展其功能,这可能是不可取的,因为它是具有给定功能的基本类型。类似地,
C#
中的structures
总是隐式密封的。因此,不能从另一个结构中派生一个结构/类。其原因是structures
仅用于建模独立的,原子的,用户定义的数据类型,我们不想修改这些数据类型。有时候,当您构建类层次结构时,您可能希望根据您的域模型或业务规则来限制继承链中的某个分支。
例如,
Manager
和PartTimeEmployee
都是Employee
,但您在组织中的兼职员工之后没有任何角色。在这种情况下,您可能需要密封PartTimeEmployee
以防止进一步的分支。另一方面,如果您有小时或周兼职员工,则从PartTimeEmployee
继承它们可能是有意义的。kh212irz4#
我认为这篇文章有一些好的观点,具体的情况是当试图将一个非密封类转换为任何随机接口时,编译器不会抛出错误;但是当使用sealed的时候编译器会抛出它不能转换的错误。Sealed类带来了额外的代码访问安全性。
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla
5kgi1eie5#
密封是一个有意识的决定,只有当你想清楚地揭示你的类的结构特征时才应该考虑。它是关于你的对象模型的结构选择。它永远不应该是关于性能或安全性()的决定。但更重要的是,永远不应该是关于对你的继承树的任意限制。
我提出这个经验法则:* 如果你不得不考虑密封一个类是否是一个好主意,那么永远不应该密封它。密封一个类的决定对你来说应该是显而易见的,甚至在你编写该类的第一行代码之前就已经做出了。*
举个例子,因为我们不能从它们派生,但是它们看起来很像一个普通的类,我们通常认为结构体是密封的类。这就是它们。正是这种限制允许它们实现值类型语义,因为继承和多态只能与引用类型一起工作。所以“结构体类”是密封的,因为任何实现值类型的类-类型语义必须给予继承,并以不同的方式管理其内存。(注意,这适用于C#中的任何值类型对象,而不仅仅是结构)。
另一个例子:代码生成器可以编写表示窗口及其所有元素的密封类,以供用户定义其行为,因为UI引擎期望这个类而不是其他类,以便能够呈现窗口。
最后一个例子:一个数学工具类可能是密封的,因为它是围绕真理构建的,任何扩展的行为都不可能是正确的或“按预期工作”。这是一个不完全属于上述经验法则的例子。永远不要盲目相信经验法则。
()如果性能是应用程序中的一个问题,那么可以确定未密封的类不是原因。同样,如果依赖密封类来强制应用程序中的安全性,那么问题一定出在基类上--它们公开了什么或允许扩展什么。
6qqygrtg6#
如果你的设计模式是使用单例,你会希望密封类,这样只能创建一个示例。基本上,密封类,创建一个私有构造函数,和公共静态方法来返回类。