導入
ファイル・DB接続・ネットワークなど「使い終わったら閉じる必要がある資源」は、閉じ忘れると枯渇します。IDisposable は「後片付けの作法」を型に持たせるインターフェースで、using はそのブロックを抜けるときに必ず片付けを呼んでくれる構文です。
図解
flowchart LR
U["using (var r = new Resource())"] --> B["ブロック内の処理"]
B --> D["ブロックを抜けると自動で<br/>r.Dispose() が呼ばれる"]
style D fill:#e8f5e9
サンプル
using (var r = new Resource("DB"))
{
r.Use();
} // ← ここで自動的に r.Dispose() が呼ばれる
// using 宣言(波かっこ省略)ならスコープの終わりで片付く
using var log = new Resource("Log");
log.Use();
class Resource : IDisposable
{
private readonly string _name;
public Resource(string name) { _name = name; Console.WriteLine($"{_name} を開いた"); }
public void Use() => Console.WriteLine($"{_name} を使用");
public void Dispose() => Console.WriteLine($"{_name} を閉じた");
}
出力:
DB を開いた
DB を使用
DB を閉じた
Log を開いた
Log を使用
Log を閉じた
IDisposableのDispose()に後片付けを書くusingはブロック(またはスコープ)を抜けるとき、例外が起きても必ずDispose()を呼ぶ- 資源を扱う型は基本
IDisposable。usingで包むのが定石
やってみよう
using を外して new Resource("X").Use(); だけにすると「閉じた」が出ないことを確かめ、using の有無で後片付けが変わることを体感しましょう。
演習
// TODO: Dispose で "closed" を出力する IDisposable な Handle を定義し、using で使ってください
___
using (var h = new Handle())
{
Console.WriteLine("working");
}
// 期待: working → closed の順で出力される
- 期待される出力:
working\nclosed
ヒント1を見る
class Handle : IDisposable { public void Dispose() => Console.WriteLine("closed"); }
ヒント2を見る
using ブロックを抜けると Dispose() が呼ばれるので、“working” の後に “closed” が出ます
まとめ
IDisposableは「後片付けの作法」を型に持たせるusingはスコープを抜けるとき必ずDispose()を呼ぶ(例外時も)- 資源を扱う型は
usingで包むのが定石
次回: デザインパターンコースへ。再利用できる設計の「型」を学びます。