bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] IDisposeの役割と使いどころ

[C#] IDisposeの役割と使いどころ

Mar 16, 2026 C# , .NET bucket-sort

前の記事で整理したアンマネージドリソースの問題に対して、.NETではその解決手段として IDisposable という仕組みが用意されています。ここでは、その役割や設計の考え方、基本的な使い方について整理します。

IDisposableとは何か

IDisposable は、アンマネージドリソース(およびそれに準ずるリソース)を 明示的に解放するための仕組み です。

public interface IDisposable
{
    void Dispose();
}

インターフェース自体は非常にシンプルですが、この Dispose() には明確な意味があります。

「このオブジェクトはもう使い終わったので、保持しているリソースを解放する」 という合図です。

C#では通常、メモリの解放はGCが自動で行ってくれます。しかし、それとは別に「自分で終わりを明示しなければならないもの」が存在し、そのための共通ルールとして用意されているのが IDisposable です。

なぜ必要なのか

前提として、GCが扱っているのは「マネージドメモリ」だけです。 これは前の記事で整理した通りです。

GCの動作は非常にシンプルで、

  • オブジェクトへの参照があるかどうか
  • 参照がなければ回収する

というルールで動いています。

ここで重要なのは、「リソースが使われているかどうか」は見ていない という点です。

例えば、次のコードを考えます。

var stream = new FileStream("test.txt", FileMode.Open);

このとき実際には、

  • OS側にファイルハンドルが作られる
  • C#オブジェクトがそれを保持する

という構造になっています。

問題の本質

  • GCが見ているのは「FileStreamオブジェクト」だけ
  • OSのファイル状態は認識していない

そのため、

  • ファイルが開いたままになる
  • 解放タイミングが不定になる

といった問題が発生します。

この「GCでは制御できない領域」を扱うために IDisposable が必要になります。

基本的な使い方(using)

IDisposableの最も基本的な使い方は using 文です。

using (var stream = new FileStream("test.txt", FileMode.Open))
{
    // 処理
}

この構文は単なる便利記法ではなく、内部的には次のような構造になります。

var stream = new FileStream(...);
try
{
    // 処理
}
finally
{
    stream.Dispose();
}

ポイント

  • 例外が発生しても必ずDisposeされる
  • スコープ終了時に解放される

つまり、「確実にリソースを解放するための仕組み」 として機能します。

どんなものが対象か

IDisposableが関係するのは、主に「外部リソースを扱うもの」です。

典型例

  • FileStream(ファイル)
  • StreamReader
  • Socket(通信)
  • SqlConnection(DB接続)

これらはすべて、「開く/使う/閉じる」というライフサイクルを持つ という共通点があります。

また、直接アンマネージドリソースを扱っていなくても、

間接的なケース

  • 内部でアンマネージドリソースを持つクラス
  • 内部に IDisposable を持つクラス

も対象になります。

ここで重要なのは、「.NETのクラスだから安全」というわけではない という点です。

重要な理解:オブジェクトとリソースは別

IDisposableを理解する上で重要なのは、この構造です。

var stream = new FileStream(...);

実際の構造

層 内容
C#オブジェクト マネージド
内部のリソース アンマネージド

つまり、マネージドオブジェクトがリソースを“保持しているだけ” です。

この構造のため、

  • オブジェクトの寿命
  • リソースの寿命

は必ずしも一致しません。

このズレを埋めるのが Dispose の役割です

設計の本質

IDisposableの設計で最も重要なのは、「誰が解放責任を持つか」です。

基本ルール

  • 自分で生成したリソース → 自分でDisposeする
  • 外から渡されたリソース → 勝手にDisposeしない

例:所有している場合

class A : IDisposable
{
    private FileStream _stream;

    public A()
    {
        _stream = new FileStream(...);
    }

    public void Dispose()
    {
        _stream.Dispose();
    }
}

この場合、A がリソースの所有者なので、解放責任も A にあります。

例:借りている場合

class A
{
    private Stream _stream;

    public A(Stream stream)
    {
        _stream = stream;
    }
}

この場合、Stream の所有者は呼び出し側なので、AはDisposeしない(責任を持たない) が正解です。

IDisposableは連鎖する

もう一つ重要な性質として、「Disposeは上位に伝播する」というものがあります。

構造

A → B → C → FileStream
  • FileStreamがリソースを持つ
  • Cがそれを保持
  • BがCを保持
  • AがBを保持

最終的にAまで責任が伝わります。

実務的なルール

IDisposableを持つフィールドがある場合、自分もIDisposableになる可能性が高い

自分で実装する場合

シンプルなパターン

public class Sample : IDisposable
{
    private bool _disposed;

    public void Dispose()
    {
        if (_disposed) return;

        // リソース解放

        _disposed = true;
    }
}

本格パターン

public class Sample : IDisposable
{
    private bool _disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        if (disposing)
        {
            // マネージドリソース
        }

        // アンマネージドリソース

        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~Sample()
    {
        Dispose(false);
    }
}

これは「アンマネージドリソースを直接扱う場合」に必要になるパターンです。

よくある落とし穴

  • Disposeを忘れる → リソースが解放されない
  • Dispose後に使う → ObjectDisposedException
  • スレッドをまたいでDispose → 状態不整合の原因

まとめ

IDisposableの本質

  • 明示的にリソースを解放するための仕組み
  • GCでは扱えない領域を補う

設計の核心

  • 「所有者が解放責任を持つ」

実務ルール

  • IDisposableはusingで扱う
  • 自分で生成したものは自分でDispose
  • 渡されたものは勝手にDisposeしない

最重要ポイント

  • オブジェクトの寿命とリソースの寿命は別

この理解があると、「なぜDisposeが必要なのか」「なぜusingを書くのか」が自然に繋がるようになります。

C# .NET
← [C#] アンマネージドリソースとは [C#] ネイティブハンドルを安全にラップするSafeHandle →

Related Posts

  • [C#] delegate と event の仕組みを整理する Apr 1, 2026
  • Pub/Sub パターンとは何か Mar 31, 2026
  • [C#] Interlockedの使い方 Mar 27, 2026
  • [C#] ImmutableHashSet<T>の使い方 Mar 26, 2026

Table of Contents

  • IDisposableとは何か
  • なぜ必要なのか
    • 問題の本質
  • 基本的な使い方(using)
    • ポイント
  • どんなものが対象か
    • 典型例
    • 間接的なケース
  • 重要な理解:オブジェクトとリソースは別
    • 実際の構造
  • 設計の本質
    • 基本ルール
    • 例:所有している場合
    • 例:借りている場合
  • IDisposableは連鎖する
    • 構造
    • 実務的なルール
  • 自分で実装する場合
    • シンプルなパターン
    • 本格パターン
  • よくある落とし穴
  • まとめ
    • IDisposableの本質
    • 設計の核心
    • 実務ルール
    • 最重要ポイント

Recent Posts

  • Laravel の Event / Listener で Pub/Sub を実装する Apr 2, 2026
  • [C#] delegate と event の仕組みを整理する Apr 1, 2026
  • Pub/Sub パターンとは何か Mar 31, 2026
  • PHP/Laravel で値の状態を判定するヘルパ関数まとめ Mar 30, 2026
  • Filament の dehydrated メソッドとは何か Mar 29, 2026

Categories

  • AWS27
  • C#22
  • .NET20
  • Laravel16
  • Linux12
  • Apache8
  • MySQL8
  • PHP8
  • DynamoDB6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • セキュリティ3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • AWS
  • C#
  • .NET
  • Laravel
  • PHP
  • MySQL
  • セキュリティ
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • DoS
  • Nginx
  • Windows
  • WordPress
  • パフォーマンス
  • 監視
  • Amazon Linux 2023
  • CMS
  • Docker
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • 認可
  • Aurora
  • Blade
Powered by Hugo & Explore Theme.