根据一些初步测试,看起来它可以做到,但我想知道的是它是否保证能够返回结果,或者在某些情况下是否无法返回?这对我的应用程序至关重要,但我还没有找到一个不会返回结果的使用情况。
我想了解这个问题的专业知识。
根据一些初步测试,看起来它可以做到,但我想知道的是它是否保证能够返回结果,或者在某些情况下是否无法返回?这对我的应用程序至关重要,但我还没有找到一个不会返回结果的使用情况。
我想了解这个问题的专业知识。
其他答案中存在不准确之处。
当控制流程通过return
, goto
, break
, continue
, 或者简单地运行到尽头而“正常” 离开try块时,控制传递到finally块。如果通过被封闭的catch块捕获了异常而离开try块,则控制将传递到finally块。
在所有其他情况下,不能保证一定会调用finally块中的代码。特别是:
如果try块中的代码进入无限循环或线程被冻结且永远不会解冻,则永远不会调用finally块中的代码。
如果进程在调试器中暂停,然后被强制终止,则不会调用finally块。如果进程执行fail-fast操作,则不会调用finally块。
如果电源线从插座中拔出,则不会调用finally块。
如果抛出异常但没有相应的catch块,则是否运行finally块是运行时实现的“实现细节”。运行时可以在未捕获异常出现时选择任何行为。 "不运行finally块"和"运行finally块"都是"任何行为"的示例,因此可以选择任何一个。通常,运行时会要求用户在finally块运行之前附加调试器;如果用户拒绝,则运行finally块。但是:运行时不需要这样做。它可能会直接执行fail-fast操作。
您不能依赖于always被调用的finally块。如果您需要关于代码执行的强有力保证,则不应编写try-finally,而应编写受限执行区域。正确编写CER是C#编程中最困难的任务之一,因此在尝试编写代码之前,请仔细研究文档。
顺便说一句,“finally-blocked gotos”的“有趣事实”是:
try { goto X; } finally { throw y; }
X : Console.WriteLine("X");
X是一个无法到达的标签,被一个可到达的goto所指定!所以下次你在派对上可以说:“嘿,大家有谁能写一个C#程序,其中有一个无法到达的标签被一个可到达的goto所指定?”然后你就可以看看哪些人读过可达性规范,哪些人没有啦!
void X() { try { ObtainAdminPowers(); DoSomethingDangerous(); } finally { ReleaseAdminPowers(); }}
,并且 DoSomethingDangerous
抛出了一个异常。现在假设我们有 try { X(); } catch (Exception) when (M()) { }
。方法 M()
在管理员权限被释放之前运行!X
的作者认为除了 DoSomethingDangerous
之外,没有其他代码会使用管理员权限,但是作者是错误的! - Eric Lippertvoid X() { try { Obtain(); DoIt(); } catch { Release(); throw; } Release(); }
,任何明智的人都不会写出这样的代码。这是.NET异常中不幸存在的安全设计缺陷之一。 - Eric Lipperttry { M } finally { N }
的意义与 { try { M } catch (Exception e) { N; throw; } N }
不同。我理解其动机,但不禁想知道是否可以在不引入完全不同的异常相关基元的情况下实现它。 - Joker_vD通常情况下,finally块中的代码将被执行,无论try或catch块中发生了什么事情。如果你从方法中返回或不返回都没有关系。
但是,有些情况下这并不是真的。例如,如果finally块中的代码抛出异常,它将像任何其他代码块一样停止执行。
Eric Lippert撰写了一个更全面的答案,概述了其他情况:https://dev59.com/RGkv5IYBdhLWcg3w6lHj#10260233
对于goto,答案仍然是肯定的。考虑以下代码:
try
{
Console.WriteLine("Inside the Try");
goto MyLabel;
}
finally
{
Console.WriteLine("Inside the Finally");
}
MyLabel:
Console.WriteLine("After the Label");
执行后的输出结果如下:
在 Try 语句块内
在 Finally 语句块内
标签后面
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();
}
try
{
Console.WriteLine("Try");
throw new Exception();
}
finally
{
Console.WriteLine("finally");
}
finally
块。 - N. M.如果出现终止应用程序的致命异常,Finally块将不会被调用。这包括堆栈溢出、在调用方法时JIT期间发生的异常以及CLR运行时内部的致命异常。
正如@mintech所指出的,如果应用程序在块内挂起,它将根本无法到达finally块。这包括等待同步对象、死锁、无限循环甚至没有关闭方式的UI。