我正在为朋友查看一些代码,并说他在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
}
}
答案 0 :(得分:245)
简单回答:是的。
答案 1 :(得分:196)
通常,是的。 finally部分保证执行包括异常或return语句在内的任何操作。此规则的一个例外是线程上发生异步异常(OutOfMemoryException
,StackOverflowException
)。
要了解有关异步异常和可靠代码的更多信息,请阅读constrained execution regions。
答案 2 :(得分:143)
这是一个小测试:
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
答案 3 :(得分:35)
从MSDN引用
最终用于保证代码语句块的执行,无论前面的尝试块是如何退出。
答案 4 :(得分:18)
一般来说,终于会运行。
对于以下三种情况,最终将始终运行:
以下场景,终于不会运行:
Asynchronous StackOverflowException。
从.NET 2.0开始,堆栈溢出将导致进程终止。除非应用进一步约束以使最终成为CER(约束执行区域),否则最终将不会运行。 CER不应用于一般用户代码。它们只应在清理代码始终运行至关重要的地方使用 - 在所有进程关闭堆栈溢出之后,所有托管对象都将默认清理。因此,CER应该与之相关的唯一地方是在流程外部分配的资源,例如,非托管句柄。
通常,非托管代码在被用户代码使用之前由某个托管类包装。托管包装器类通常会使用SafeHandle来包装非托管句柄。 SafeHandle实现了一个关键的终结器,以及一个在CER中运行的Release方法,以保证执行清理代码。因此,您不应该看到CERs遍布用户代码。
因此,最终不会在StackOverflowException上运行的事实应该对用户代码没有影响,因为该进程无论如何都会终止。如果你有一些边缘情况你需要清理一些非托管资源,在SafeHandle或CriticalFinalizerObject之外,那么使用CER如下;但请注意,这是不好的做法 - 非托管概念应该被抽象为托管类和适当的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.
}
答案 5 :(得分:9)
这是一个非常重要的例外,我在其他任何答案中都没有提到过,而且(在用C#编程18年之后),我无法相信我没有这样做。知道。
如果你在catch
区块中抛出或触发任何排序的例外(不仅仅是奇怪的StackOverflowExceptions
和那种类似的东西),你就不会这样做。 t将整个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();
}
我确定这是有原因的,但奇怪的是它并不广为人知。 (例如,它注意到here,但在这个特定问题的任何地方都没有。)
答案 6 :(得分:7)
我意识到我迟到了派对但是在场景中(与OP的例子不同)确实抛出异常MSDN状态(https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx):“如果未捕获异常,执行finally块取决于操作系统是否选择触发异常展开操作。“
如果调用堆栈中的某些其他函数(例如Main)捕获异常,则finally块仅保证执行。这个细节通常不是问题,因为所有运行时环境(CLR和OS)C#程序都在进程退出时拥有的大多数资源(文件句柄等)上运行。在某些情况下,它可能是至关重要的:正在进行的数据库操作正在进行中,您要提交resp。放松;或某些远程连接,可能无法由操作系统自动关闭,然后阻止服务器。
答案 7 :(得分:3)
是。这实际上是最终陈述的要点。除非发生某些事情(内存不足,计算机未插入等),否则应始终执行finally语句。
答案 8 :(得分:2)
如果你要退出应用程序,最后不会运行 System.exit(0);如在
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
结果只是: 尝试
答案 9 :(得分:2)
它也不会触发未捕获的异常并在Windows服务中托管的线程中运行
Finally is not executed when in a Thread running in a Windows Service
答案 10 :(得分:0)
99%的方案可以保证finally
块中的代码能够运行,但是,请考虑这种情况:您的线程有try
- > {{阻止(无finally
)并在该线程中得到未处理的异常。在这种情况下,线程将退出并且不会执行其catch
块(在这种情况下应用程序可以继续运行)
这种情况非常罕见,但只是为了表明答案并非始终如此"是",大部分时间都是"是"有时,在极少数情况下," No"。
答案 11 :(得分:0)
finally块的主要目的是执行其中的任何内容。它不应该依赖于try或catch中发生的任何事情。但是对于System.Environment.Exit(1),应用程序将退出而不移动到下一行代码。