一般的にはい、finally が実行されます。
次の 3 つのシナリオでは、finally は常に実行されます。
- 例外は発生しません
- 同期例外(通常のプログラム フローで発生する例外)。
これには、System.Exception から派生する CLS 準拠の例外と、System.Exception から派生しない非 CLS 準拠の例外が含まれます。非 CLS 準拠の例外は、RuntimeWrappedException によって自動的にラップされます。C# は非 CLS 準拠の例外をスローできませんが、C++ などの言語はスローできます。C# は、CLS に準拠していない例外をスローできる言語で記述されたコードを呼び出している可能性があります。
- 非同期 ThreadAbortException
.NET 2.0 以降、ThreadAbortException は、finally の実行を妨げなくなりました。ThreadAbortException は、finally の前または後にホイストされるようになりました。スレッド アボートが発生する前に try が実際に入力されている限り、finally は常に実行され、スレッド アボートによって中断されることはありません。
次のシナリオでは、finally は実行されません。
非同期 StackOverflowException。
.NET 2.0 以降では、スタック オーバーフローによりプロセスが終了します。finally を CER (Constrained Execution Region) にするためにさらに制約が適用されない限り、finally は実行されません。CER は、一般的なユーザー コードでは使用しないでください。これらは、クリーンアップ コードを常に実行することが重要な場合にのみ使用する必要があります。スタック オーバーフローですべてのプロセスがシャットダウンされ、すべての管理対象オブジェクトがデフォルトでクリーンアップされた後です。したがって、CER が関連する唯一の場所は、プロセスの外部で割り当てられたリソース (たとえば、アンマネージ ハンドル) です。
通常、アンマネージ コードは、ユーザー コードによって使用される前に、何らかのマネージ クラスによってラップされます。マネージ ラッパー クラスは通常、SafeHandle を使用してアンマネージ ハンドルをラップします。SafeHandle は、重要なファイナライザーと、クリーンアップ コードの実行を保証するために CER で実行される Release メソッドを実装します。このため、ユーザー コード全体に散らばる CER を確認する必要はありません。
したがって、最終的に StackOverflowException で実行されないという事実は、プロセスがいずれにせよ終了するため、ユーザー コードには影響しません。SafeHandle または CriticalFinalizerObject の外部で、管理されていないリソースをクリーンアップする必要があるエッジ ケースがある場合は、次のように CER を使用します。ただし、これは悪い習慣であることに注意してください。管理されていない概念は、設計により、管理されたクラスと適切な SafeHandle に抽象化する必要があります。
例えば、
// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This is *NOT* a CER
}
finally
{
// This is a CER; guaranteed to run, if the try was entered,
// even if a StackOverflowException occurs.
}