MimiCatLab
← ホームに戻る

C# の sealed とは?継承を制御して設計を明確にする

C# の sealed をクラスとメソッドで使い分ける方法、判断の目安、注意点を短く解説します。

sealed とは

sealed は、C# で「ここから先の継承や上書きは許可しない」と示すキーワードです。型の使われ方を明確にし、意図しない拡張による不具合を防ぐために使います。

用途は二つあります。クラス全体を継承不可にする方法と、オーバーライドしたメソッドだけを最終実装にする方法です。

クラスを継承不可にする

public sealed class ApiClient
{
    public void Send(string message)
    {
        // API を呼び出す
    }
}

// コンパイル エラー
// public class CustomApiClient : ApiClient { }

クラスに sealed を付けると、そのクラスを基底クラスにできなくなります。「このクラスの振る舞いは完成している」「派生クラスで変更されると安全性を保てない」というときに向いています。

たとえば、値オブジェクト、認証まわりの型、外部サービスを包む小さなクライアントなどは、むやみに継承を許可しないほうが読みやすくなることがあります。差し替えが必要なら、継承ではなくインターフェースを用意する設計も選べます。

メソッドを最終実装にする

sealed は、派生クラスで override したメソッドにも付けられます。この場合はクラスの継承を許しつつ、そのメソッドだけをこれ以上上書きできなくします。

public class Document
{
    public virtual string GetTitle() => "Untitled";
}

public class Report : Document
{
    public sealed override string GetTitle() => "Monthly report";
}

Report は継承できますが、GetTitle はさらにオーバーライドできません。継承階層の途中で、ある振る舞いを確定したい場合に便利です。

判断の目安

使うか迷ったら、「この型を誰かが継承したときも、基底クラスの前提を安全に守れるか」を考えます。答えがノーなら、sealed を検討する価値があります。

  • 継承による拡張を設計として想定していない
  • 不変性や検証ルールを必ず守らせたい
  • テスト用の差し替えをインターフェースで表現できる

一方で、フレームワークが継承による拡張を前提にしている場合や、利用者にカスタマイズを委ねたい場合は、最初から閉じないほうが自然です。

パフォーマンス目的だけで使う?

sealed により、実行環境が仮想呼び出しを最適化しやすくなる場合はあります。ただし通常は、体感できるほどの差にはなりません。性能のために先回りして付けるより、「継承を許可するか」という設計上の意思を優先するのがおすすめです。

まとめ

sealed は、単に制限を加える機能ではなく、「この型やメソッドはここまで」と境界を伝える言葉です。拡張ポイントを意図して用意するときだけ継承を開き、それ以外は必要に応じて閉じる。小さな判断ですが、後から読みやすく壊れにくいC#の設計につながります。