DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

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

Finally文がどのような時に実行され、どのような時に実行されないかに関しては「Insider.NET」の「連載:VB.NETプログラミング 第16回 例外処理を極める Finally文の確実性」で詳しく述べられています。これによるとほとんどのケースでFinally文は実行されるということになっています。しかしここにある以外にもさらにいろいろなケースがあるのではと考え、そのような状況でもFinally文が実行されるのかを実験してみました。

まずは次のようにTryブロック内を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

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

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

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

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

次は別スレッドで実行した時の例です。この場合スレッドをAbortメソッドにより中断するとFinally文は実行されますが、スレッド実行中にアプリケーションを終了させた場合、Finally文は実行されませんので注意が必要です。

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

Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button1.Click
    'スレッド開始
    t = New System.Threading.Thread(AddressOf thread1)
    t.IsBackground = True
    t.Start()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button2.Click
    'スレッド終了
    t.Abort()
End Sub

Sub thread1()
    Try
        '無限ループ
        Do
        Loop
    Finally
        Console.WriteLine("Finally called")
    End Try

    '以下、出力例
    'Finally called
End Sub
C#
コードを隠すコードを選択
System.Threading.Thread t;

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 Button2_Click(object sender, System.EventArgs e)
{
    //スレッド終了
    t.Abort();
}

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

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