DOBON.NET

Finally文が実行されないケースはあるか?

エラー処理(例外処理)の基本」で説明したように、Try...FinallyステートメントのFinallyブロックは、Tryブロックがどのような形で終了しても実行されます。しかし本当にそうなのか、色々なケースで実験してみました。

Returnでメソッドを抜ける

次のようにReturnでメソッドを抜けた場合、Finally文は実行されました。

VB.NET
コードを隠すコードを選択
Shared Sub FinallyTest()
    Try
        Return
    Finally
        Console.WriteLine("Finally called")
    End Try
End Sub
C#
コードを隠すコードを選択
static void FinallyTest()
{
    try
    {
        return;
    }
    finally
    {
        Console.WriteLine("Finally called");
    }
}

Exit(break)でループを抜ける

Exit(break)でループを抜けた時も、Finally文は実行されました。Continueでジャンプしても、やはり実行されます。

VB.NET
コードを隠すコードを選択
While True
    Try
        Exit While
    Finally
        Console.WriteLine("Finally called")
    End Try
End While
C#
コードを隠すコードを選択
while (true)
{
    try
    {
        break;
    }
    finally
    {
        Console.WriteLine("Finally called");
    }
}

GoToでジャンプする

GoToでジャンプしても、Finally文は実行されました。

VB.NET
コードを隠すコードを選択
Try
    GoTo Jump
Finally
    Console.WriteLine("Finally called")
End Try
Jump:
Console.WriteLine("Jump")

'以下、出力例
'Finally called
'Jump
C#
コードを隠すコードを選択
try
{
    goto Jump;
}
finally
{
    Console.WriteLine("Finally called");
}
Jump:
Console.WriteLine("Jump");

//以下、出力例
//Finally called
//Jump

Application.Exitメソッドでアプリケーションを終了する

Windowsアプリケーションにおいて、Tryブロック内でフォームを閉じてプログラムを終了した時もFinally文は実行されました。Application.ExitメソッドApplication.ExitThreadメソッドで終了した時も、実行されます。

VB.NET
コードを隠すコードを選択
Try
    Me.Close()
Finally
    Console.WriteLine("Finally called")
End Try
C#
コードを隠すコードを選択
try
{
    this.Close();
}
finally
{
    Console.WriteLine("Finally called");
}

Environment.Exitメソッドでアプリケーションを終了する

次のようにEnvironment.Exitメソッドでアプリケーションを終了した時は、Finallyが実行されませんでした。

VB.NETのEndステートメントはEnvironment.Exitメソッドと同じですので、やはりFinallyは実行されません。

VB.NET
コードを隠すコードを選択
Try
    Environment.Exit(0)
Finally
    Console.WriteLine("Finally called")
End Try
C#
コードを隠すコードを選択
try
{
    Environment.Exit(0);
}
finally
{
    Console.WriteLine("Finally called");
}

Environment.FailFastメソッドでアプリケーションを終了する

.NET Framework 2.0で追加されたEnvironment.FailFastメソッドは、MSDNの説明にある通り、Finallyを実行せずにプロセスを終了させます。

VB.NET
コードを隠すコードを選択
Try
    Environment.FailFast("テストです。")
Finally
    Console.WriteLine("Finally called")
End Try
C#
コードを隠すコードを選択
try
{
    Environment.FailFast("テストです。");
}
finally
{
    Console.WriteLine("Finally called");
}

バックグラウンドスレッドを中断する

今度は別スレッド(バックグラウンドスレッド)で実行した時の例です。この場合スレッドをAbortメソッドで中断するとFinally文は実行されます。しかし、スレッド実行中にアプリケーションを終了させた場合は、Finally文は実行されませんでした。

VB.NET
コードを隠すコードを選択
Private t As System.Threading.Thread

'Button1のClickイベントハンドラ
Private Sub Button1_Click(sender As Object, e As System.EventArgs) _
        Handles Button1.Click
    'スレッド開始
    t = New System.Threading.Thread( _
        New System.Threading.ThreadStart(AddressOf thread1))
    t.IsBackground = True
    t.Start()
End Sub

Private Sub thread1()
    Try
        '無限ループ
        While True
        End While
    Finally
        Console.WriteLine("Finally called")
    End Try
End Sub

'Button2のClickイベントハンドラ
Private Sub Button2_Click(sender As Object, e As System.EventArgs) _
        Handles Button1.Click
    'スレッド終了
    t.Abort()
End Sub

'Button3のClickイベントハンドラ
Private Sub Button3_Click(sender As Object, e As EventArgs) _
        Handles Button1.Click
    'アプリケーション終了
    Application.Exit()
End Sub
C#
コードを隠すコードを選択
System.Threading.Thread t;

//Button1のClickイベントハンドラ
private void Button1_Click(object sender, System.EventArgs e)
{
    //スレッド開始
    t = new System.Threading.Thread(new System.Threading.ThreadStart(thread1));
    t.IsBackground = true;
    t.Start();
}

private void thread1()
{
    try
    {
        //無限ループ
        for (; ; ) { }
    }
    finally
    {
        Console.WriteLine("Finally called");
    }
}

//Button2のClickイベントハンドラ
private void Button2_Click(object sender, System.EventArgs e)
{
    //スレッド終了
    t.Abort();
}

//Button3のClickイベントハンドラ
private void Button3_Click(object sender, EventArgs e)
{
    //アプリケーション終了
    Application.Exit();
}

まとめ

Finallyブロックは、ほとんどの場合、実行されます。ただし、以下のような場合は実行されません。

  • Environment.ExitやEnvironment.FailFastメソッドでアプリケーションを終了した時。
  • バックグラウンドスレッドが実行中にアプリケーションを終了した時。
  • (上では紹介しませんでしたが、)破損状態例外が発生した時。ファイナライザで例外が発生した時、タスクマネージャー等でプロセスが強制的に終了させられた時など。
  • 履歴:
  • 2013/6/20 Return、Exit、Environment.Exit、Environment.FailFastについての説明を追加。まとめを追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。
共有する

この記事への評価

この記事へのコメント

この記事に関するコメントを投稿するには、下のボタンをクリックしてください。投稿フォームへ移動します。通常のご質問、ご意見等は掲示板へご投稿ください。