.Netフレームワークのシールされたクラスの大部分の背後にある動機は何ですか。クラスを封印する利点は何ですか?継承を許可しないことがどのように役立つか、そしておそらくこれらのクラスと戦っている唯一の人ではないかもしれません。
では、なぜフレームワークはこのように設計されているのか、そしてすべてを開封するという画期的な変更ではないのでしょうか?別の理由があるに違いないが、ただ悪であるのか?
.Netフレームワークのシールされたクラスの大部分の背後にある動機は何ですか。クラスを封印する利点は何ですか?継承を許可しないことがどのように役立つか、そしておそらくこれらのクラスと戦っている唯一の人ではないかもしれません。
では、なぜフレームワークはこのように設計されているのか、そしてすべてを開封するという画期的な変更ではないのでしょうか?別の理由があるに違いないが、ただ悪であるのか?
回答:
このトピックに関するMSDNの記事は、クラスのシーリングによる拡張性の制限です。
クラスは継承のために設計するか、継承を禁止する必要があります。継承の設計にはコストがかかります。
これについては、効果的なJavaの項目17で詳しく説明します。Javaのコンテキストで記述されているという事実に関係なく、アドバイスは.NETにも適用されます。
個人的には、クラスが.NETでデフォルトでシールされていることを望みます。
と思われるシール上のMicrosoftの公式ガイドラインは、この質問は、9年前〜尋ねると、彼らはオプトアウト(デフォルトで密封していない)にオプトインの哲学(デフォルトでシール)から移動してから進化してきました:
X正当な理由がない限り、クラスを封印しないでください。
拡張性シナリオを考えることができないためにクラスを封印することは、正当な理由ではありません。フレームワークのユーザーは、便利なメンバーを追加するなど、さまざまな自明ではない理由でクラスから継承することを好みます。ユーザーが型から継承したい明白でない理由の例については、封印されていないクラスを参照してください。
クラスを封印する正当な理由は次のとおりです。
- クラスは静的クラスです。静的クラスの設計を参照してください。
- このクラスは、セキュリティ上重要な秘密を継承された保護メンバーに格納します。
- クラスは多くの仮想メンバーを継承し、それらを個別にシールするコストは、クラスをシールしないままにしておくことの利点を上回ります。
- クラスは、非常に高速なランタイムルックアップを必要とする属性です。封印された属性は、封印されていない属性よりもわずかに高いパフォーマンスレベルを持っています。属性を参照してください。
Xシールされた型では、保護されたメンバーまたは仮想メンバーを宣言しないでください。
定義により、シールされた型は継承できません。つまり、シールされた型の保護されたメンバーは呼び出せず、シールされた型の仮想メソッドはオーバーライドできません。
✓オーバーライドするシーリングメンバーを検討します。バーチャルメンバー(バーチャルメンバーで説明)の導入によって発生する可能性のある問題は、オーバーライドにも当てはまりますが、程度はやや低くなります。オーバーライドを封印すると、継承階層のその時点から始まるこれらの問題から保護されます。
実際、ASP.Net Core codebaseを検索するとsealed class
、約30のオカレンスしか見つかりません。そのほとんどは属性とテストクラスです。
不変性の保全は封印を支持する良い議論だと私は思います。
たとえば、パフォーマンスは重要な要素です。たとえば、Javaの文字列クラスはfinal(<-Sealed)であり、その理由はパフォーマンスのみです。別の重要なポイントは、ここで詳細に説明されている脆弱な基本クラスの問題を回避することだと思います:http : //blogs.msdn.com/ericlippert/archive/2004/01/07/virtual-methods-and-brittle-base-classes。 aspx
フレームワークを提供する場合、レガシープロジェクトの保守性にとって重要であり、脆弱な基本クラスの問題を回避するためにフレームワークをアップグレードすることが重要です
String
、たとえそれが最終的でなかったとしても、クラスはサブクラス化さえできないかもしれません。
シーリングにより、いくつかのマイナーなパフォーマンスの向上を実現できます。これは、JITやレイジーペシミゼーションの世界では、C ++などの世界よりも当てはまりませんが、.NETはペシミゼーションほど良くないので、Javaコンパイラーは主に異なる設計哲学のため、依然として有用です。これは、vtableを介して間接的に呼び出すのではなく、仮想メソッドを直接呼び出すことができることをコンパイラーに伝えます。
また、平等比較などの「閉じた世界」が必要な場合にも重要です。通常、仮想メソッドを定義すると、実際にそのアイデアを実装する等価比較の概念を定義することにかなり夢中になります。一方、仮想メソッドを使用して、クラスの特定のサブクラスに対してそれを定義できる場合があります。そのクラスを封印することで、平等が本当に成り立つことが保証されます。
クラス、メソッド、またはプロパティをシールするかどうかを決定するには、一般的に次の2つの点を考慮する必要があります。
•クラスをカスタマイズする機能を通じて、派生クラスが得る潜在的な利点。
•派生クラスがクラスを変更して、正しく機能しなくなったり、期待どおりに機能しなくなる可能性。
さらに考慮すべきことは、単体テストでシールされたクラスをスタブ化できないことです。Microsoftのドキュメントから:
封印されたクラスまたは静的メソッドは、スタブ型が仮想メソッドのディスパッチに依存しているため、スタブできません。このような場合は、「shimを使用してアプリケーションを他のアセンブリから分離して単体テストを行う」で説明されているように、shimタイプを使用します。