真/偽の答えを期待していた別のインタビューの質問で、よくわかりませんでした.
9 に答える
finally
ほとんどの場合実行されます。ほとんどすべての場合です。たとえば、非同期例外(、、StackOverflowException
などOutOfMemoryException
)ThreadAbortException
がスレッドでスローされた場合、finally
実行は保証されません。これが、信頼性の高いコードを記述するために制約された実行領域が存在する理由です。
インタビューの目的で、私はこの質問への答えが間違っていることを期待しています(私は何も保証しません!インタビュアーはこれを自分で知らないかもしれません!)。
通常、finally
ブロックの実行は保証されています。
ただし、エラーが発生した場合にCLRを強制的にシャットダウンする場合もあります。そのような場合、finally
ブロックは実行されません。
そのような例の1つは、StackOverflow例外が存在する場合です。
たとえば、finally
ブロックの下のコードでは実行されません。
static void Main(string[] args) {
try {
Foo(1);
} catch {
Console.WriteLine("catch");
} finally {
Console.WriteLine("finally");
}
}
public static int Foo(int i) {
return Foo(i + 1);
}
私が知っているもう1つのケースは、ファイナライザーが例外をスローした場合です。その場合、プロセスも直ちに終了するため、保証は適用されません。
以下のコードは問題を示しています
static void Main(string[] args) {
try {
DisposableType d = new DisposableType();
d.Dispose();
d = null;
GC.Collect();
GC.WaitForPendingFinalizers();
} catch {
Console.WriteLine("catch");
} finally {
Console.WriteLine("finally");
}
}
public class DisposableType : IDisposable {
public void Dispose() {
}
~DisposableType() {
throw new NotImplementedException();
}
}
どちらの場合も、プロセスはcatch
との両方の前に終了しfinally
ます。
例は非常に工夫されていることを認めますが、それらは要点を説明するために作成されたものです。
幸いなことに、どちらも頻繁には発生しません。
MSDNから直接:
finally ブロックは、try ブロックで割り当てられたリソースをクリーンアップするのに役立ちます。try ブロックの終了方法に関係なく、制御は常に finally ブロックに渡されます。
catch は、ステートメント ブロックで発生する例外を処理するために使用されますが、finally は、前の try ブロックがどのように終了したかに関係なく、コードのステートメント ブロックが実行されることを保証するために使用されます。
http://msdn.microsoft.com/en-us/library/zwc8s4fz(VS.71,loband).aspx
最終的に常に実行されるというのは完全に真実ではありません。Haackedからのこの回答を参照してください:
2つの可能性:
StackOverflowException
ExecutingEngineException
StackOverflowExceptionが発生した場合、スタックにはそれ以上コードを実行する余地がないため、finallyブロックは実行されません。また、非常にまれなExecutingEngineExceptionが発生した場合も呼び出されません。
ただし、これら2つの例外は回復できない例外であるため、基本的にプロセスは終了します。
Mehrdadが述べたように、信頼できるtry / catch / finalは、Constrained Execution Regions(CER)を使用する必要があります。例はMSDNによって提供されます:
[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
public IntPtr m_outputHandle;
}
sealed class MySafeHandle : SafeHandle
{
// Called by P/Invoke when returning SafeHandles
public MySafeHandle()
: base(IntPtr.Zero, true)
{
}
public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}
return sh;
}
}
はい、finally は常に実行されます。
一般に、finally ブロックは、例外がスローされるかどうか、および例外が処理されるかどうかに関係なく、常に実行されます。
いくつかの例外があります (詳細については、他の回答を参照してください)。
最後に、その try catch ブロックに対して毎回発生します
「最後に」は、例外がスローされるかどうかに関係なく実行されます。
開いている接続を閉じるのに適した場所です。実行の成功または失敗に関係なく、接続を管理したり、ファイルを開いたりできます。
最後に常に実行されます。tryブロックがどのように機能するかに依存しません。tryとcathの両方で追加の作業を行う必要がある場合は、finallyブロックに入れることをお勧めします。したがって、常に実行されることを保証できます。