另一个面试问题是期待一个真/假的答案,我不太确定。
9 回答
finally
大部分时间被执行。这几乎是所有情况。例如,如果在线程上抛出异步异常(如StackOverflowException
, OutOfMemoryException
, ),则无法保证执行。这就是为编写高度可靠的代码而存在约束执行区域的原因。ThreadAbortException
finally
出于面试目的,我希望这个问题的答案是错误的(我不会保证任何事情!面试官自己可能不知道这一点!)。
直接来自 MSDN:
finally 块对于清理在 try 块中分配的任何资源很有用。不管 try 块如何退出,控制总是传递给 finally 块。
catch 用于处理语句块中发生的异常,而 finally 用于保证语句块的执行,而不管前面的 try 块如何退出。
http://msdn.microsoft.com/en-us/library/zwc8s4fz(VS.71,loband).aspx
通常,该finally
块保证执行。
但是,在少数情况下会强制 CLR 在出现错误时关闭。在这些情况下,finally
不会运行该块。
一个这样的例子是存在 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);
}
我知道的另一种情况是终结器是否抛出异常。在这种情况下,该过程也会立即终止,因此该保证不适用。
下面的代码说明了问题
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
。
我承认这些例子非常做作,但它们只是为了说明这一点。
幸运的是,这两种情况都不经常发生。
是的,finally 总是被执行。
finally 总是会被执行的说法并不完全正确。请参阅Haacked的这个答案:
两种可能:
StackOverflowException
ExecutingEngineException
当存在 StackOverflowException 时,finally 块将不会被执行,因为堆栈上没有空间可以执行更多代码。出现ExecutingEngineException时也不会调用,这种情况非常少见。
但是,这两个异常是您无法恢复的异常,因此基本上您的进程无论如何都会退出。
正如 Mehrdad 所提到的,可靠的 try/catch/finally 必须使用受约束的执行区域 (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 块中
无论是否抛出异常,都会执行“Finally”。
它是关闭任何打开的连接的好地方。执行成功或失败,您仍然可以管理您的连接或打开文件。
finally 总是被执行。我不依赖于 try 块的工作方式。如果你必须为 try 和 cath 做一些额外的工作,最好放入 finally 块。所以你可以保证它总是被执行。