いつ、なぜクラスを封印しますか?


87

C#およびC ++ / CLIでは、キーワードsealed(またはNotInheritableVB)を使用して、クラスを継承の可能性から保護します(クラスは継承できません)。オブジェクト指向プログラミングの特徴の1つが継承であることを知っていますが、を使用するsealedとこの機能に反し、継承が停止するように感じます。sealedそれを使用することの利点と重要な時期を示す例はありますか?

回答:


96
  1. 元のオブジェクトを「偽装」できないように、セキュリティ機能を実装するクラス。

  2. より一般的には、最近Microsoftの担当者と交換しました。この担当者は、継承を処理しないとパフォーマンス面でコストがかかるため、継承を本当に意味のある場所に制限しようとしていると言っていました。
    封印されたキーワードは、メソッドを探すためのクラスがこれ以上ないことをCLRに通知し、処理を高速化します。

現在市場に出回っているほとんどのパフォーマンス向上ツールには、継承されていないすべてのクラスを封印するチェックボックスがあります。
ただし、MEFを介してプラグインまたはアセンブリの検出を許可する場合は、問題が発生するので注意してください。


3
特に、サードパーティによって再利用されてから(MEFを介して)コードベースに再統合される場合は、再利用されたライブラリのクラスを封印することに注意する必要がありました。コードベースは特定のクラスを継承しない場合がありますが、サードパーティは継承します。
Louis Kottmann 2015

10
理由#1は曖昧に聞こえますが、ほとんどの場合「セキュリティ機能」を記述していないと仮定すると、理由#1はほとんど当てはまらないということですか?理由#2は、パフォーマンスチューニングのためです。どのくらいのパフォーマンスの違いについて話しているのですか?それらは、非セキュリティクラスの定義を変更することを正当化するのに十分重要ですか?答えが「はい」の場合でも、これは理想的にはコンパイラオプション、つまり開発者にコードベースを変更させるのではなく、「すべての非シールクラス用に最適化されたコードを生成する」です。
RayLuo 2017年

1
処理せずに放置する、パフォーマンスの面でコストが高くなります。これは、非常識な数のクレイジーテストでさえ測定可能ですか?
t3chb0t 2017

4
シーリングは最悪です。テストが難しくなります。FakeItEasyを使用していくつかのASP.NETクラスをモックしたいのですが、封印されているためできません。
好戦的なチンパンジー

2
@RayLuoにこれ以上同意することはできません。私は、セキュリティとパフォーマンスが実際には問題にならないクラスを人々が封印したことを何度か思いました。彼らの「封印された」ことは、クラスをオーバーライドするという私の合理的な必要性を単に妨げ、物事をはるかに困難にしました。Warlike Chimpanzeeが言ったように、クラスをあざけることはテストではとても一般的です。
ZZY

15

ヒヒの優れた答えへの補遺:

  1. クラスが継承用に設計されていない場合、サブクラスはクラスの不変条件を壊す可能性があります。もちろん、これはパブリックAPIを作成している場合にのみ当てはまりますが、経験則として、サブクラス化するように明示的に設計されていないクラスはすべて封印します。

関連する注記として、封印されていないクラスにのみ適用されます。作成されたメソッドvirtualはすべて拡張ポイントであるか、少なくとも拡張ポイントである必要があるように見えます。メソッドvirtualを宣言することも、意識的な決定である必要があります。(C#ではこれは意識的な決定ですが、Javaではそうではありません。)


編集:いくつかの関連リンク:

Kotlinはデフォルトでクラスをシールすることにも注意してください。そのopenキーワードは、JavafinalまたはsealedC#の反対です。(確かに、これが良いことであるという普遍的な合意はありません。)


25
クラスを封印すると、利益よりも頭痛の種が多くなります。私は、開発者がクラスを封印している状況を絶えず見つけており、単純であるべきものに何時間もの困難を引き起こしています。クラスの封印をやめなさい、あなたはあなたが思っているほど機知に富んでいない。必要な場合にのみクラスを封印し、それでも再考する必要があります。私の意見ですが、私が編集/開封できない他の人の封印されたクラスに対処しなければならない人として。
ガントラボルド

9
@GantManのコメントは、基本的に「いつ?ほとんど。なぜ?これがあなたがそうしない理由です」と答えるので、OPの質問に対する答えの1つと実際に見なされるべきです。コメントを別の回答として再投稿し、投票を集める必要があることを認めてください。:-)
RayLuo 2017年

1
これはこの答えに関連していました:stackoverflow.com/a/7777674/3195477 ?人に(のみ)名前を付けるよりも、リンクする方がよい
UuDdLrLrSs

2

クラスをとしてマークすると、Sealedセキュリティを危険にさらしたり、パフォーマンスに影響を与えたりする可能性のある重要なクラスの改ざんを防ぐことができます。

多くの場合、クラスを封印することは、変更したくない固定された動作を持つユーティリティクラスを設計するときにも意味があります。

たとえば、のSystem名前空間はC#、など、封印された多くのクラスを提供しますString。封印されていない場合、その機能を拡張することが可能ですが、これは特定の機能を備えた基本的なタイプであるため、望ましくない場合があります。

同様に、structuresinC#は常に暗黙的に封印されています。したがって、ある構造/クラスを別の構造から派生させることはできません。この理由は、変更したくないスタンドアロンのアトミックなユーザー定義データ型structuresのみをモデル化するために使用されるためです。

クラス階層を構築するときに、ドメインモデルまたはビジネスルールに基づいて、継承チェーンの特定のブランチを制限したい場合があります。

たとえば、aManagerPartTimeEmployeeは両方ともEmployeesですが、組織のパートタイム従業員の後は何の役割もありません。この場合、PartTimeEmployeeそれ以上の分岐を防ぐためにシールすることをお勧めします。一方、時間単位または週単位のパートタイムの従業員がいる場合は、から継承するのが理にかなっている場合がありPartTimeEmployeeます。


Stringクラスを拡張することはどのように望ましくないでしょうか?文字列は現在とまったく同じように機能し、必要に応じて追加機能を備えた派生クラスを作成できます。どのような問題について話しているのでしょうか。
ケビンウェルズ

また、継承階層を「制限」するポイントは何でしょうか。それはあなたがその階層を拡張する必要がなかった場合は、単に非効率的である、最初の親クラスを開封しなければならないことを意味する
ケビン・ウェルズ

EricLippertからのこのすばらしい投稿とこのSOの質問をチェックしてください。
AkshayKhot19年

1
その答えでさえ、基本的に「なぜ文字列を派生させたいのですか?」に要約され、次に文字列を派生させたい理由(たとえば、nullで終了する文字列)に言及し、継承せずに回避する必要があると述べています。なぜあなたは、単に最初の場所で開封のまま、オープン、あなたの選択肢を残すことができ、後にするとき、それを回避するには、それをより複雑にし、持っている
ケビン・ウェルズ

2番目の質問の目標は、(ビジネスロジックに応じて)望ましくない動作を防ぐことです。unsealクラスを封印してそれに依存するすべてのクラスを壊すよりも、必要に応じて後でクラスに参加する方が簡単です。
AkshayKhot19年

0

この投稿にはいくつかの良い点があると思います。特定のケースは、シールされていないクラスを任意のランダムインターフェイスにキャストしようとしたときに、コンパイラがエラーをスローしないことでした。ただし、sealedを使用すると、コンパイラは変換できないというエラーをスローします。封印されたクラスは、追加のコードアクセスセキュリティをもたらします。
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla


1
ソリューションへのリンクは大歓迎ですが、それがなくても回答が役立つことを確認してください。リンクの周りにコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてから、ページの最も関連性の高い部分を引用してください。ターゲットページが利用できない場合に再リンクします。リンクに過ぎない回答は削除される場合があります。
Baum mitAugen

申し訳ありませんが、回答として投稿するつもりはありませんでしたが、他の回答とは関係がないようで、どこに置く
かわかり

1
私は提案に従って投稿を編集しました。もともとは違う角度で貢献したいのですが(たぶん)、反対票をもらっただけで、内容についてはまだ話していませんでしたが、-1で理由を教えていただけませんか?
strisunshine 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.