如果我在 Try 块中返回值,Finally 语句中的代码会触发吗?
-
19-08-2019 - |
题
我正在为一位朋友检查一些代码,并说他在 try-finally 块内使用了 return 语句。即使 try 块的其余部分不触发,Finally 部分中的代码是否仍会触发?
例子:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
解决方案
简单的回答:是
其他提示
通常情况下,是的。最后部分保证执行发生的任何情况,包括异常或返回语句。此规则的一个例外是线程上发生的异步异常(OutOfMemoryException
, StackOverflowException
).
要了解有关异步异常和该情况下可靠代码的更多信息,请阅读 受限执行区域.
这里有一个小测试:
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("before");
Console.WriteLine(test());
Console.WriteLine("after");
}
static string test()
{
try
{
return "return";
}
finally
{
Console.WriteLine("finally");
}
}
}
其结果是:
before
finally
return
after
这MSDN引用
<强>最后强>用于保证不管代码语句块如何执行前述的尝试强>块的退出强>
通常是的,最终将运行。
对以下三种情况下,最终将 总是 运行:
- 没有例外情况发生
- 同步的例外 (例外情况发生在正常程序的流程)。
这包括符合CLS例外情况,获得系统。例外和不符合CLS例外情况外,不得从系统。例外。非符合CLS的例外是自动包裹的RuntimeWrappedException.C#不能扔非CLS投诉的例外情况,但语言,例如C++可以。C#可以调用代码写在一语,可以把不符合CLS例外情况。 - 异步ThreadAbortException
为。网2.0、ThreadAbortException将不再阻止一个最后运行。ThreadAbortException是现在升起来之前或之后的最后。最终会一直运行和不被中断由一个线程中止,只要的尝试是实际输入之前线的中断发生。
下面的方案,最后将不会运行:
异步StackOverflowException.
为。网2.0一堆溢出将导致该进程终止。最终会不可行,除非进一步的限制是适用于使最后一个核证的排减量(约束的执行地区)。核证的排减量不应当用一般用户代码。他们只应当使用至关重要的是,清洁代码一直运行--在所有的过程中被关闭在栈溢流无论如何和所有的托管对象,因此将清理的默认。因此,只有一个核证的排减量应该是相关的是对于资源分配之外的进程,例如,非托管处理。
通常,非托管的代码包括通过一些管理课之前被消耗的用户代码。该管理包装类将通常使用的一个SafeHandle包裹不受管处理。该SafeHandle实现了一个重要的终结,和释放方法是运行中的核证的排减量,以保证执行清理的编码。出于这个原因,你不应该看到的核证的排减量充斥通过用户代码。
所以事实上,最后没有上运行StackOverflowException应该没有影响到用户代码,由于该进程将终止。如果你有一些边的情况你需要清洗-一些不受管理的资源之外,一个SafeHandle或CriticalFinalizerObject,然后利用CER作为下;但请注意,这是不好实践--将不受管理的概念应被抽象到一个管理类别(es)和适当的SafeHandle(s)通过设计。
例如,
// 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.
}
有对这个非常重要的例外,我还没有看到任何其他的答案中提到,并(在C#编程了18年后),我不相信,我不知道。
如果你扔或引发的异常的任何的排序里面你catch
块(不只是奇怪StackOverflowExceptions
和之流的东西),而且你没有内的另一个try/catch/finally
块整个try/catch
块,你finally
块将不会执行。这是很容易证明 - 如果我还没有看到它自己,因为多久我读过,这只是很奇怪,微小的角落情况下,可能会导致一个finally
块不执行,我也不会相信。
static void Main(string[] args)
{
Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
try
{
Console.WriteLine("Inside try but before exception.");
throw new Exception("Exception #1");
}
catch (Exception ex)
{
Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
throw;
}
finally
{
Console.WriteLine("This never gets executed, and that seems very, very wrong.");
}
Console.WriteLine("This never gets executed, but I wasn't expecting it to.");
Console.ReadLine();
}
我敢肯定有一个原因,但它的怪异,它不是更广为人知。 (它指出例如href="https://stackoverflow.com/a/28483789/68231">,但在这个特殊的问题没有在任何地方。)
我意识到我迟到了,但在方案(从OP的例子不同),其中确实有异常抛出MSDN状态(的 https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ):的” 如果异常没有被捕获,执行的最后块取决于强>上的操作系统是否选择触发异常放松操作“。
在最后块仅保证到,如果一些其它的功能(如主)进一步调用堆栈向上捕捉异常执行。这个细节通常不是一个问题,因为所有的运行时环境(CLR和OS)C#程序上的免费资源最多运行一个进程拥有,当它退出(文件句柄等)。在某些情况下,它可能是至关重要的,但:要提交RESP数据库操作的一半正在进行中。放松;或一些远程连接,该连接可以不通过OS,然后阻止服务器自动关闭。
是的。这是在事实要点的最后发言。除非有catestrophic发生(在存储器、计算机拔出,等等。) 在最后发言总是应该以执行。
它也不会开火,未捕获的异常,并在Windows服务托管的线程中运行
最后惯于在运行的情况下如果从应用程序退出使用 System.exit(0);如在
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
结果将是公正: 尝试
这将保证该finally
块中的代码将运行情景的99%,但是,觉得这个场景:你必须具有try
-> finally
块(无catch
)一个线程,你会得到一个未处理该线程中的异常。在这种情况下,该线程将退出及其finally
块将不被执行(该应用可以继续在这种情况下运行)
这情况是非常罕见的,但它只是表明,答案并不总是“是的”,这是大部分的时间“是”有时,在罕见的情况下,“否”。
最后块的主要目的是为执行无论是在其内部写入。它不应该依赖于在尝试或catch.However与System.Environment.Exit(1)应用程序将退出而不移动到下一行代码无论发生什么情况。