bucket-sort logo bucket-sort

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

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] Disposable Objects — IDisposable / Dispose() と using 構文

[C#] Disposable Objects — IDisposable / Dispose() と using 構文

May 12, 2026 C# , .NET bucket-sort

前の記事では Finalize() を整理し、ファイナライザは 「Dispose の呼び忘れに対する保険」 に過ぎないことを確認しました。では本来の解放手段である Dispose() とは何か、なぜそれが望ましいのか——この記事では IDisposable インターフェースと Dispose() メソッド、そして using 構文の使い方を整理します。

IDisposable の基本については既存の記事でも触れていますが、ここでは Finalize の代替 という観点から、より深く掘り下げます。

なぜ Finalize() の代替が必要か

Finalize() には次のような根本的な弱点があります。

  • タイミングが不定:いつ呼ばれるか分からない
  • GC を重くする:ファイナライズキュー、世代昇格
  • 保証がない:プロセス強制終了時には呼ばれない
  • スレッドが 1 本:詰まると全体に波及

つまり、「リソースを必要なくなった瞬間に解放したい」という当然の要求に Finalize() だけでは答えられません。

そこで登場するのが、呼び出し側が「もう要らない」と明示的に宣言する仕組み ——IDisposable です。

IDisposable インターフェース

IDisposable の定義は驚くほどシンプルです。

namespace System
{
    public interface IDisposable
    {
        void Dispose();
    }
}

たった 1 つのメソッドだけ。しかしこの Dispose() には、

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

という強い意味が込められています。

Finalize() との違い

観点 Finalize() Dispose()
呼び出す主体 GC 呼び出し側コード
呼び出しタイミング 不定 呼んだ瞬間
確実性 保証なし 呼べば必ず実行
対象 アンマネージドのみ推奨 マネージド・アンマネージド両方 OK
GC への負担 大 なし

Dispose() は 決定論的(deterministic)な解放 を提供します。これが Finalize() との最大の違いです。

using 文 — Dispose を確実に呼ぶ

Dispose() を呼び忘れたら本末転倒です。そこで C# は using 文という構文糖を用意しています。

using (var stream = new FileStream("test.txt", FileMode.Open))
{
    // stream を使う処理
}
// ここでスコープを抜けると同時に stream.Dispose() が呼ばれる

これは内部的に try/finally に展開されます。

var stream = new FileStream("test.txt", FileMode.Open);
try
{
    // stream を使う処理
}
finally
{
    stream?.Dispose();
}

ポイントは、

  • 例外が発生しても必ず Dispose される
  • スコープを抜けたタイミングで解放される
  • 書き忘れにくい

ということ。「リソースを開いたら、その場で using で囲む」が C# の基本作法です。

複数リソースの using

using は入れ子にできますし、変数を並べることもできます。

// 入れ子(暗黙のブロック省略形)
using (var conn = new SqlConnection(connStr))
using (var cmd = conn.CreateCommand())
{
    // ...
}

// 同じ型なら並列宣言も可能
using (FileStream a = File.OpenRead("a.txt"),
                  b = File.OpenRead("b.txt"))
{
    // ...
}

解放順は 後に宣言したものから先に Dispose(LIFO)されます。

using 宣言(C# 8.0)

C# 8.0 では、より簡潔な書き方として using 宣言(using declaration) が導入されました。波括弧でブロックを作らず、変数宣言の前に using を付けるだけです。

public void ReadFile(string path)
{
    using var stream = new FileStream(path, FileMode.Open);
    using var reader = new StreamReader(stream);

    string content = reader.ReadToEnd();
    Console.WriteLine(content);

    // メソッドを抜けるときに reader → stream の順に Dispose される
}

何が変わったか

  • インデントが深くならない:従来の using (...) { ... } のブロック地獄から解放される
  • スコープは「変数を宣言したスコープの終わり」まで:通常はメソッド末尾、if/for の中なら そのブロックの終わり
  • 解放順は逆順(LIFO)

従来の using 文との使い分け

状況 推奨
リソースをメソッド全体で使う using 宣言
一部のスコープでだけ使いたい using 文(ブロック)
すぐに Dispose したい区切りがある using 文(ブロック)

例えば「ファイルを読み終わったらすぐ閉じて、その後に重い処理をしたい」場合は、明示的なブロックの方が意図が伝わります。逆に、メソッド全体でリソースを使うだけなら、using 宣言の方が読みやすいです。

public string ReadAndProcess(string path)
{
    string content;
    using (var reader = new StreamReader(path))
    {
        content = reader.ReadToEnd();
    } // ここで明示的にファイルを閉じる

    // ファイルを閉じてから重い処理
    return ExpensiveTransform(content);
}

IAsyncDisposable(C# 8.0+)

非同期で解放処理を行いたいケースのために、IAsyncDisposable が追加されました。

public interface IAsyncDisposable
{
    ValueTask DisposeAsync();
}

非同期で I/O フラッシュやネットワーク切断を行いたいリソース(Stream、DbConnection の一部、gRPC チャネルなど)が実装しています。

await using 構文で扱います。

public async Task ProcessAsync()
{
    await using var conn = new SqlConnection(connStr);
    await conn.OpenAsync();
    // ...
} // メソッド終了時に await conn.DisposeAsync() が呼ばれる

IAsyncDisposable と IDisposable の両方を実装する型もあります(FileStream など)。非同期コンテキストでは await using を優先 すると覚えておけば十分です。

Dispose の使いどころ

Dispose を実装すべき・呼ぶべきケースをまとめます。

実装すべきクラス

  • アンマネージドリソース(OS ハンドル、ネイティブメモリなど)を直接持つ
  • 内部に IDisposable フィールドを持つ
  • イベントハンドラを購読しており、解除する必要がある
  • 接続・セッション・ロックなど、明示的な「終了」が必要

呼び出し側のルール

  • 自分で生成した IDisposable は自分で破棄する:using で囲むのが基本
  • 引数で渡された IDisposable は勝手に破棄しない:呼び出し側が所有者
  • フィールドに保持した IDisposable は、保持しているクラスも IDisposable にする

このあたりの所有権の考え方は既存記事でも整理しています。

Finalize と Dispose の関係

両者は対立するものではなく、役割分担 をします。

  • Dispose:通常の解放経路。決定論的・即時。
  • Finalize:Dispose を呼び忘れたときの最後の保険。GC 任せ。

両方持つクラスでは、Dispose() の中で GC.SuppressFinalize(this) を呼んで「もうファイナライザは不要」と GC に伝えるのが定石です。具体的なコードパターンは次の記事で示します。

まとめ

項目 内容
インターフェース System.IDisposable / System.IAsyncDisposable
中核メソッド Dispose() / DisposeAsync()
呼び出し方法 using 文、using 宣言(C# 8.0+)、await using
Finalize との違い 決定論的・即時・GC 負担なし
基本ルール 所有者が解放する。using で囲む

Finalize() は GC 任せの「保険」、Dispose() は呼び出し側が握る「正規の解放経路」。普段書くべきはほぼ常に Dispose 側 です。次の記事では、Finalizable と Disposable の両方を備えた 完全な Dispose パターン を、サンプルコードとともに整理します。

C# .NET IDisposable Dispose Using メモリ管理
← [C#] Finalizable Objects — Finalize() の役割と使いどころ [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 →

Related Posts

  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] IDisposeの役割と使いどころ Mar 16, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026
  • [C#] System.GC クラスを整理する — ガベージコレクションを制御するための API May 10, 2026

Table of Contents

  • なぜ Finalize() の代替が必要か
  • IDisposable インターフェース
    • Finalize() との違い
  • using 文 — Dispose を確実に呼ぶ
    • 複数リソースの using
  • using 宣言(C# 8.0)
    • 何が変わったか
    • 従来の using 文との使い分け
  • IAsyncDisposable(C# 8.0+)
  • Dispose の使いどころ
    • 実装すべきクラス
    • 呼び出し側のルール
  • Finalize と Dispose の関係
  • まとめ

Recent Posts

  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026
  • [C#] System.GC クラスを整理する — ガベージコレクションを制御するための API May 10, 2026
  • [C#] IComparable と IComparer — オブジェクトの順序比較と複数ソート戦略 May 9, 2026

Categories

  • C#63
  • .NET62
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • パフォーマンス
  • DoS
  • Nginx
  • Windows
  • WordPress
  • メモリ管理
  • 監視
  • 設計
  • Amazon Linux 2023
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • オブジェクト指向
  • クラス設計
  • コレクション
  • デザインパターン
  • パターンマッチング
  • 継承
  • 認可
  • Aurora
  • Blade
  • Grafana
  • Hugo
  • InfluxDB
  • Policy
  • Record
  • SSG
  • インターフェース
  • エラーハンドリング
  • カプセル化
  • ガベージコレクション
  • モニタリング
  • 例外
Powered by Hugo & Explore Theme.