C# 如果我在 Try 块中返回值,是否会触发 finally 语句中的代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/345091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Will code in a Finally statement fire if I return a value in a Try block?
提问by JamesEggers
I'm reviewing some code for a friend and say that he was using a return statement inside of a try-finally block. Does the code in the Finally section still fire even though the rest of the try block doesn't?
我正在为一位朋友审查一些代码,并说他在 try-finally 块中使用了 return 语句。即使 try 块的其余部分没有触发,Finally 部分中的代码是否仍然触发?
Example:
例子:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
采纳答案by Andrew Rollings
Simple answer: Yes.
简单的回答:是的。
回答by Mehrdad Afshari
Normally, yes. The finally section is guaranteed to execute whatever happens including exceptions or return statement. An exception to this rule is an asynchronous exception happening on the thread (OutOfMemoryException
, StackOverflowException
).
通常,是的。finally 部分保证执行任何发生的事情,包括异常或返回语句。此规则的一个例外是发生在线程 ( OutOfMemoryException
, StackOverflowException
)上的异步异常。
To learn more about async exceptions and reliable code in that situations, read about constrained execution regions.
要了解有关这种情况下的异步异常和可靠代码的更多信息,请阅读受约束的执行区域。
回答by Jeffrey L Whitledge
Yes. That is in fact that main point of a finally statement. Unless something catestrophic occurs (out of memory, computer unplugged, etc.) the finally statement should always be executed.
是的。这实际上是 finally 语句的要点。除非发生灾难性的事情(内存不足、计算机被拔掉等),否则应该始终执行 finally 语句。
回答by Perpetualcoder
Quoting from MSDN
引用自 MSDN
finallyis used to guarantee a statement block of code executes regardless of how the preceding tryblock is exited.
finally用于保证无论前面的try块如何退出,语句块都会执行。
回答by Jon B
Here's a little test:
这是一个小测试:
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");
}
}
}
The result is:
结果是:
before
finally
return
after
回答by markn
Generally yes, the finally will run.
一般是的,finally 会运行。
For the following three scenarios, the finally will ALWAYSrun:
对于以下三个场景, finally 将始终运行:
- No exceptions occur
- Synchronous exceptions(exceptions that occur in normal program flow).
This includes CLS compliant exceptions that derive from System.Exception and non-CLS compliant exceptions, which do not derive from System.Exception. Non-CLS compliant exceptions are automatically wrapped by the RuntimeWrappedException. C# cannot throw non-CLS complaint exceptions, but languages such as C++ can. C# could be calling into code written in a language that can throw non-CLS compliant exceptions. - Asynchronous ThreadAbortException
As of .NET 2.0, a ThreadAbortException will no longer prevent a finally from running. ThreadAbortException is now hoisted to before or after the finally. The finally will always run and will not be interrupted by a thread abort, so long as the try was actually entered before the thread abort occurred.
- 没有异常发生
- 同步异常(正常程序流中发生的异常)。
这包括派生自 System.Exception 的符合 CLS 的异常和不派生自 System.Exception 的不符合 CLS 的异常。不符合 CLS 的异常由 RuntimeWrappedException 自动包装。C# 不能抛出非 CLS 投诉异常,但诸如 C++ 之类的语言可以。C# 可能会调用用可以抛出不符合 CLS 的异常的语言编写的代码。 - 异步 ThreadAbortException
从 .NET 2.0 开始,ThreadAbortException 将不再阻止 finally 运行。ThreadAbortException 现在被提升到 finally 之前或之后。finally 将始终运行并且不会被线程中止中断,只要在线程中止发生之前实际进入了尝试。
The following scenario, the finally will not run:
以下场景,finally不会运行:
Asynchronous StackOverflowException.
As of .NET 2.0 a stack overflow will cause the process to terminate. The finally will not be run, unless a further constraint is applied to make the finally a CER (Constrained Execution Region). CERs should not be used in general user code. They should only be used where it is critical that clean-up code always run -- after all the process is shutting down on stack overflow anyway and all managed objects will therefore be cleaned-up by default. Thus, the only place a CER should be relevant is for resources that are allocated outside of the process, e.g., unmanaged handles.
异步 StackOverflowException。
从 .NET 2.0 开始,堆栈溢出将导致进程终止。finally 将不会运行,除非应用进一步的约束使 finally 成为 CER(受约束的执行区域)。CER 不应在一般用户代码中使用。它们应该只在清理代码始终运行至关重要的情况下使用——毕竟所有进程在堆栈溢出时都会关闭,因此默认情况下所有托管对象都将被清理。因此,CER 唯一应该相关的地方是分配在进程之外的资源,例如非托管句柄。
Typically, unmanaged code is wrapped by some managed class before being consumed by user code. The managed wrapper class will typically make use of a SafeHandle to wrap the unmanaged handle. The SafeHandle implements a critical finalizer, and a Release method that is run in a CER to guarantee the execution of the clean-up code. For this reason, you should not see CERs littered through-out user code.
通常,非托管代码在被用户代码使用之前由某个托管类包装。托管包装类通常会使用 SafeHandle 来包装非托管句柄。SafeHandle 实现了一个关键终结器和一个在 CER 中运行的 Release 方法,以保证清理代码的执行。因此,您不应看到 CER 散落在用户代码中。
So the fact that the finally doesn't run on StackOverflowException should have no effect to user code, since the process will terminate anyway. If you have some edge case where you do need to clean-up some unmanaged resource, outside of a SafeHandle or CriticalFinalizerObject, then use a CER as follows; but please note, this is bad practice -- the unmanaged concept should be abstracted to a managed class(es) and appropriate SafeHandle(s) by design.
因此,finally 不在 StackOverflowException 上运行这一事实应该对用户代码没有影响,因为该进程无论如何都会终止。如果您确实需要清理 SafeHandle 或 CriticalFinalizerObject 之外的某些非托管资源,请按以下方式使用 CER;但请注意,这是不好的做法——非托管概念应该被抽象为托管类和适当的 SafeHandle 设计。
e.g.,
例如,
// 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.
}
回答by Hakuna Matata
finally wont run in case if you are exiting from the application using System.exit(0); as in
如果您使用 System.exit(0) 退出应用程序,最终将不会运行;如
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
the result would be just : try
结果将只是:尝试
回答by Peter - Reinstate Monica
I realize I'm late to the party but in the scenario (differing from the OP's example) where indeed an exception is thrown MSDN states (https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx): "If the exception is not caught, execution of the finally block dependson whether the operating system chooses to trigger an exception unwind operation."
我意识到我迟到了,但在场景中(与 OP 的示例不同)确实抛出了异常 MSDN 状态(https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx):“如果没有捕获异常,finally块的执行取决于操作系统是否选择触发异常展开操作。”
The finally block is only guaranteedto execute if some other function (such as Main) further up the call stack catches the exception. This detail is usually not a problem because all run time environments (CLR and OS) C# programs run on free most resources a process owns when it exits (file handles etc.). In some cases it may be crucial though: A database operation half underway which you want to commit resp. unwind; or some remote connection which may not be closed automatically by the OS and then blocks a server.
只有在调用堆栈更靠后的某个其他函数(例如 Main)捕获到异常时,finally 块才能保证执行。这个细节通常不是问题,因为所有运行时环境(CLR 和 OS)C# 程序都在进程退出时拥有的大部分免费资源(文件句柄等)上运行。但在某些情况下,这可能很重要:您想要提交的数据库操作正在进行中。放松; 或者某些远程连接可能不会被操作系统自动关闭然后阻止服务器。
回答by Stig
It will also not fire on uncaught exception and running in a thread hosted in a Windows Service
它也不会触发未捕获的异常并在 Windows 服务中托管的线程中运行
Finally is not executed when in a Thread running in a Windows Service
回答by Jonathan Perry
99% of the scenarios it will be guaranteed that the code inside the finally
block will run, however, think of this scenario: You have a thread that has a try
->finally
block (no catch
) and you get an unhandled exception within that thread. In this case, the thread will exit and its finally
block will not be executed (the application can continue to run in this case)
99% 的场景将保证finally
块内的代码将运行,但是,请考虑以下场景:您有一个具有try
->finally
块(否catch
)的线程,并且您在该线程中遇到了未处理的异常。在这种情况下,线程将退出,并且finally
不会执行其块(在这种情况下,应用程序可以继续运行)
This scenario is pretty rare, but it's only to show that the answer is not ALWAYS "Yes", it's most of the time "Yes" and sometimes, in rare conditions, "No".
这种情况非常罕见,但这只是表明答案并不总是“是”,大部分时间都是“是”,有时在极少数情况下是“否”。