web-dev-qa-db-ja.com

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

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

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

  2. より一般的には、Microsoftの人と最近やり取りしました。彼は、継承を本当に意味のある場所に制限しようとしたと言ったのです。
    sealedキーワードは、メソッドを探すためのクラスがこれ以上ないことをCLRに通知します。

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

89
Louis Kottmann

Baboonの優れた答えの補遺:

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

関連するメモでは、非シールクラスにのみ適用可能です。virtualで作成されたメソッドはすべて拡張ポイントであるか、少なくとも拡張ポイントであるように見えます。メソッドの宣言virtualも同様に意識的に決定する必要があります。 (C#ではこれは意識的な決定です; Javaそうではありません。)


[〜#〜] edit [〜#〜]:いくつかの関連リンク:

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

14

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

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

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

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

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

たとえば、ManagerPartTimeEmployeeは両方ともEmployeesですが、組織のパートタイム従業員の後は役割を持ちません。この場合、さらに分岐しないようにPartTimeEmployeeをシールすることができます。一方、1時間ごとまたは1週間ごとにパートタイムの従業員がいる場合、PartTimeEmployeeからそれらを継承することは理にかなっているかもしれません。

1
Akshay Khot

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

0
strisunshine