finally を使用してクリーンアップ コードを実行する方法

finally ステートメントの目的は、例外がスローされた場合でも、オブジェクト (一般に外部リソースを保持しているオブジェクト) に対して必要なクリーンアップをすぐに実行できるようにすることです。 次のように、共通言語ランタイムによってオブジェクトがガベージ コレクションされるまで待機するのではなく、オブジェクトを使用した後すぐに FileStreamClose を呼び出すというのも、このようなクリーンアップの一例です。

static void CodeWithoutCleanup()
{
    FileStream? file = null;
    FileInfo fileInfo = new FileInfo("./file.txt");

    file = fileInfo.OpenWrite();
    file.WriteByte(0xF);

    file.Close();
}

上のコードを try-catch-finally ステートメントに変えるには、次のようにクリーンアップ コードを作業コードから切り離します。

static void CodeWithCleanup()
{
    FileStream? file = null;
    FileInfo? fileInfo = null;

    try
    {
        fileInfo = new FileInfo("./file.txt");

        file = fileInfo.OpenWrite();
        file.WriteByte(0xF);
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine(e.Message);
    }
    finally
    {
        file?.Close();
    }
}

try ブロック内では OpenWrite() 呼び出しの前のどの時点でも例外が発生する可能性があり、また、OpenWrite() 呼び出し自体が失敗するおそれもあるため、ファイルを閉じようとしたときに、それが開いているという保証はありません。 finally ブロックによって、Close メソッドを呼び出す前に、FileStream オブジェクトが null でないことを確認するチェックが追加されます。 この null チェックがないと、finally ブロックからその NullReferenceException がスローされる可能性がありますが、finally ブロックにおける例外のスローはできるだけ回避する必要があります。

データベース接続も、finally ブロックで閉じられる対象になります。 データベース サーバーで許可される接続数は限られていることがあるため、データベース接続はできるだけ早く閉じる必要があります。 接続を閉じる前に例外がスローされる場合は、ガベージ コレクションを待機するより、finally ブロックを使用することをお勧めします。

関連項目