外部リソースの解放には using ステートメントを使う

外部リソースは確実に破棄する

ファイルやデータベース、ネットワークなどの外部リソースを使用する .NET Framework のクラスは使い終わったら Dispose() メソッドを呼び出してリソースを開放する必要があります。
Disposeを忘れるとファイルがオープンしたままになって他から利用できなくなったり、メモリリークが発生したりする危険があるため確実に Dispose() する必要があります。

finallyで確実にDisposeする
var reader = new StreamReader(@"Sample.txt");
try
{
    string text = reader.ReadToEnd();
    Console.WriteLine(text);
}
finally
{
    reader.Dispose();
}

上記のように finally ブロックで確実に Dispose() を呼び出すこともできますが、
using ステートメント を使うともっと簡潔にスマートにコーディングできます。
(≠ 名前空間をインクルードする using ディレクティブ

usingステートメントを使ったリソースの破棄
using (var reader = new StreamReader(@"sample.txt"))
{
    string text = reader.ReadToEnd();
    Console.WriteLine(text);
}

using のブロック {} を抜けた際に自動で reader.Dispose() が呼ばれます。
名前も using なので try {...} finally {...} より意図が明確です。
また、万が一 Dispose() を忘れてしまったり、消してしまうこともなくなります。

確実に Dispose() が呼ばれる

finally と同様に例外がスローされようが途中でリターンされようが {} を抜ける際に必ず Dispose() が呼ばれます。
(IL(.NET Framework の中間言語)を見ると try {...} finally {...} が生成されているようです。)

ブロック内でreturnしてもDisposeされる
string GetText(string path)
{
    using (var reader = new StreamReader(path))
    {
        string text = reader.ReadToEnd();
        return text;
    }
}

リソースオブジェクトを複数同時に宣言する

同じ型の場合、リソースオブジェクトは1つの using で複数同時に宣言することができます。
区切りには , を使用します。
この場合、型推論 var は使用することはできません。

リソースオブジェクトを複数同時に宣言する
using (StreamReader // var は不可
    reader1 = new StreamReader(@"Sample1.txt"),
    reader2 = new StreamReader(@"Sample2.txt"),
    reader3 = new StreamReader(@"Sample3.txt"))
{
    // 外部リソースを使った処理
}

複数の using を多段重ねできる

ネストを作らず多段重ねすることができます。
一つ目の using の末尾には ;{ もついていません。

多段重ねされたusing
using (var reader = new StreamReader(@"Sample1.txt"))
using (var writer = new StreamWriter(@"sample2.txt"))
{
    // 外部路ソースを使った処理
}

注意点

以下のように、リソースオブジェクトをインスタンス化してから using ステートメントに渡すこともできますがこれは推奨されていません。
外部リソースへのアクセスがなくなっている可能性が高いですが、変数のスコープが残ってしまいます。
リソースオブジェクトの宣言は using ステートメント内で行うことが推奨されています。

例外が発生する可能性の高いコード
var reader = new StreamReader(@"Sample.txt");
using (reader)
{
    // reader を使った処理
}
// reader はスコープ内だが、
// 外部リソースへのアクセスが失われている可能性があり、
// 例外がスローされる場合がある
string line = reader.ReadLine();

また、using を使用するリソースオブジェクトは IDisposable インターフェースの Dispose メソッドを実装している必要があります。
と言っても、 .NET Framework の外部リソースを扱うクラスは IDisposable が実装されているので特に気にする必要はありません。
自作する場合でも Visual Studio では リファクタリング機能 ctrl + . で一瞬でスケルトンコードが生成できるのでそれほど面倒ではないはず。

class MyDisposableClass : IDisposable
{
    // 以下自動生成されたコード
    #region IDisposable Support
    private bool disposedValue = false; // 重複する呼び出しを検出するには

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: マネージ状態を破棄します (マネージ オブジェクト)。
            }

            // TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
            // TODO: 大きなフィールドを null に設定します。

            disposedValue = true;
        }
    }

    // TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
    // ~MyDisposableClass() {
    //   // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
    //   Dispose(false);
    // }

    // このコードは、破棄可能なパターンを正しく実装できるように追加されました。
    public void Dispose()
    {
        // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
        Dispose(true);
        // TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
        // GC.SuppressFinalize(this);
    }
    #endregion
}

ここまで読んでいただきありがとうございました。

参考

using ステートメント (C# リファレンス)
[C#]Usingを使え
C# Tips -usingを使え、使えったら使え(^^)-
C#のusingステートメントの機能

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.