いくつかの初期テストではそうなっているようですが、私が知りたいのは、それが確実に戻るのか、それとも場合によっては戻らないのかということです。これは私のアプリケーションにとって重要ですが、返されないユースケースをまだ見つけていません。
その分野の専門知識を身につけたい。
4 に答える
他の回答には多くの不正確さがあります。
制御が 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# プログラムを誰か作れないか?」と思うかもしれません。そして、パーティーの誰が到達可能性仕様を読んでいて、誰が読んでいないかがわかります!
通常の状態では、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");
生成される出力は次のとおりです。
インサイド・ザ・トライ
最後に
ラベルの後
ここではいくつかの例を示します。
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");
}
アプリケーションを終了させる致命的な例外の場合、Finally ブロックは呼び出されません。スタック オーバーフロー、呼び出すメソッドの JIT 中の例外、CLR ランタイム内の致命的な例外が含まれます。
@mintech が指摘するように、アプリケーションがブロック内でハングすると、finally ブロックに到達しません。これには、同期オブジェクトの待機、無限ループのデッドロック、またはそれを閉じる方法がない UI が含まれます。