2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# の sealed class とは?いつ使う?落とし穴は?

2
Posted at

C# の sealed class とは?いつ使う?落とし穴は?

C# の sealed は一言でいうと 「継承を禁止する」 ためのキーワードです。
クラスに付けると、そのクラスは 派生クラス(サブクラス)を作れなくなります。

public sealed class PaymentResult
{
    public bool IsSuccess { get; }
    public string Message { get; }

    public PaymentResult(bool isSuccess, string message)
    {
        IsSuccess = isSuccess;
        Message = message;
    }
}

この場合、次のような継承はコンパイルエラーになります。

public class SpecialPaymentResult : PaymentResult // ❌ sealed なので継承不可
{
}

sealed class を使う代表的な理由

1) 設計として「これ以上拡張させたくない」を明示する

継承は便利ですが、派生先で挙動が変わると安全性が落ちます。

  • セキュリティ上、振る舞いを変えられると困る
  • ライブラリの公開 API で、互換性を守りたい
  • ドメインモデルで「この概念はこれ以上派生しない」を表現したい

2) 不変・値オブジェクト的なクラスを固定化したい

「継承でプロパティ増やされたら同値性が崩れる」みたいな事故を防ぎやすいです。

3) virtual のオーバーライドを禁止できる(性能というより安全性)

sealed class にすると、そもそも継承できないので override されません。


sealed は class だけ?実は “メソッド” も sealed にできる

sealedメソッドにも付けられます(ただし条件あり)。

  • override しているメソッドに対して
  • それ以上のオーバーライドを禁止する用途
public class Base
{
    public virtual void Execute() { }
}

public class Derived : Base
{
    public sealed override void Execute()
    {
        // ここで最終確定
    }
}

public class MoreDerived : Derived
{
    // public override void Execute() {}  // ❌ sealed override なので不可
}

sealed class の「メリット / デメリット」

メリット

  • 拡張されないことが保証され、設計意図が明確
  • 想定外のオーバーライドを防げる(特に public API)
  • “継承で壊れる” 系のバグを未然に防ぎやすい

デメリット

  • テストで モックしづらい(継承ベースのモックが使えない)
  • 後から「やっぱり派生したい」が発生すると設計変更になる
  • “拡張ポイント” を奪うので、ライブラリ設計では慎重さが必要

実務でのおすすめパターン(クリーンアーキテクチャ前提)

✅ 1) 外部公開する DTO / Result を sealed にする

派生で勝手に増やされると、シリアライズや互換性が崩れがちです。

public sealed class UserProfileDto
{
    public long UserId { get; init; }
    public string HandleName { get; init; } = "";
}

✅ 2) Domain の Value Object を sealed にする

同値性や不変性を守りやすい。

✅ 3) “継承させたい” ときは interface か composition を優先

「差し替えたい=継承」ではなく、依存性は interface に寄せた方が扱いやすいです。

public interface IClock
{
    DateTime UtcNow { get; }
}

public sealed class SystemClock : IClock
{
    public DateTime UtcNow => DateTime.UtcNow;
}

この形なら SystemClock は sealed でも、テストでは IClock を差し替えできます。


sealed にすべきか迷ったときの判断基準

sealed 推奨

  • 派生されると仕様が壊れる(セキュリティ/整合性/互換性)
  • 値オブジェクト・DTO・結果モデルなど「固定したい概念」
  • 外部公開のライブラリ API(互換性を守りたい)

sealed にしない

  • 拡張ポイントとして継承を提供したいフレームワーク設計
  • プラグイン方式を想定している
  • テストで継承モック前提(ただし interface で回避しやすい)

よくある勘違い

「sealed にすると速くなる?」

“結果として” 最適化が効くケースはありますが、性能目的で sealed を付けるのは優先度低めです。
基本は 設計の意図(継承禁止) で選ぶ方が安全です。

「static class と sealed class は同じ?」

違います。

  • static class:インスタンス化不可 + 継承不可(静的メンバーのみ)
  • sealed class:インスタンス化可能だが継承不可

まとめ

  • sealed class継承禁止
  • 設計意図を明確にし、想定外の拡張を防ぐのに強い
  • テスト容易性は interface / composition で担保するのが現代的
  • 性能目的より、壊れない設計のために使うのがおすすめ
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?