43

いくつかの初期テストではそうなっているようですが、私が知りたいのは、それが確実に戻るのか、それとも場合によっては戻らないのかということです。これは私のアプリケーションにとって重要ですが、返されないユースケースをまだ見つけていません。
その分野の専門知識を身につけたい。

4

4 に答える 4

72

他の回答には多くの不正確さがあります。

制御が try ブロックを正常に終了すると、制御は finally ブロックに渡されます。外側の catch ブロックによってキャッチされた例外を介して制御が try ブロックを離れると、制御は finally ブロックに渡されます。

他のすべての状況では、finally ブロック内のコードが呼び出されるという保証はありません。特に:

  • try ブロック コードが無限ループに入るか、スレッドが凍結されており、凍結が解除されない場合は、finally ブロック コードが呼び出されることはありません。

  • プロセスがデバッガーで一時停止され、その後積極的に強制終了された場合、finally ブロックは呼び出されません。プロセスがフェイルファストを実行する場合、finally ブロックは呼び出されません。

  • 電源コードが壁から引き抜かれた場合、finally ブロックは呼び出されません。

  • 対応する catch ブロックなしでスローされた例外がある場合、finally ブロックが実行されるかどうかは、ランタイムの実装の詳細です。キャッチされていない例外がある場合、ランタイムは任意の動作を選択できます。「finally ブロックを実行しない」と「finally ブロックを実行する」の両方が「任意の動作」の例であるため、どちらかを選択できます。通常、ランタイムは、finally ブロックが実行される前に、デバッガーをアタッチするかどうかをユーザーに尋ねます。ユーザーが「いいえ」と言った場合、finally ブロックが実行されます。しかし、繰り返しますが、ランタイムはそれを行う必要はありません。すぐに失敗する可能性があります。

finally ブロックが常に呼び出されることに依存することはできません。コードの実行について強力な保証が必要な場合は、try-finally を作成するのではなく、制約付きの実行領域を作成する必要があります。CER を正しく記述することは、C# プログラミングで最も困難なタスクの 1 つであるため、コードを記述する前にドキュメントを注意深く調べてください。

ちなみに、finally-blocked goto に関する「楽しい事実」は次のとおりです。

try { goto X; } finally { throw y; } 
X : Console.WriteLine("X");

X は、到達可能な goto によってターゲットにされた到達不能なラベルです! 次回パーティーに参加するときは、「やあ、みんな、到達可能な goto のターゲットとなる、到達不能なラベルを持つ C# プログラムを誰か作れないか?」と思うかもしれません。そして、パーティーの誰が到達可能性仕様を読んでいて、誰が読んでいないかがわかります!

于 2012-04-21T15:18:18.390 に答える
51

通常の状態では、try または catch ブロック内で何が起こっても、finally ブロック内のコードが実行されます。メソッドから戻るかどうかは問題ではありません。

これが当てはまらない場合もあります。たとえば、finally ブロック内のコードが例外をスローすると、他のコード ブロックと同様に実行が停止します。

Eric Lippert は、追加のケースを概説するより包括的な回答を書いています: https://stackoverflow.com/a/10260233/53777

goto に関しては、答えはまだイエスです。次のコードを検討してください。

try
{
    Console.WriteLine("Inside the Try");
    goto MyLabel;
}
finally
{
    Console.WriteLine("Inside the Finally");
}

MyLabel:
    Console.WriteLine("After the Label");

生成される出力は次のとおりです。

インサイド・ザ・トライ

最後に

ラベルの後

于 2012-04-21T02:56:13.403 に答える
7

ここではいくつかの例を示します。

Environment.FailFast()

        try
        {
            Console.WriteLine("Try");
            Environment.FailFast("Test Fail");

        }
        catch (Exception)
        {
            Console.WriteLine("catch");
        }
        finally
        {
            Console.WriteLine("finally");
        }

出力は「試してみてください」のみです

スタックオーバーフロー

        try
        {
            Console.WriteLine("Try");
            Rec();
        }
        catch (Exception)
        {
            Console.WriteLine("catch");
        }
        finally
        {
            Console.WriteLine("finally");
        }

Recはどこにありますか:

    private static void Rec()
    {
        Rec();
    }

出力は「試行」のみで、StackOverflowが原因でプロセスが終了します。

手ぶらの例外

        try
        {
            Console.WriteLine("Try");
            throw new Exception();
        }
        finally
        {
            Console.WriteLine("finally");
        }
于 2012-04-21T15:50:34.257 に答える
1

アプリケーションを終了させる致命的な例外の場合、Finally ブロックは呼び出されません。スタック オーバーフロー、呼び出すメソッドの JIT 中の例外、CLR ランタイム内の致命的な例外が含まれます。

@mintech が指摘するように、アプリケーションがブロック内でハングすると、finally ブロックに到達しません。これには、同期オブジェクトの待機、無限ループのデッドロック、またはそれを閉じる方法がない UI が含まれます。

于 2012-04-21T03:06:01.707 に答える