[英]in C# is it possible to force control to pass through a finally block if an exception is thrown by an associated catch block?
I know that in Java, if an exception is caught by a catch clause and its catch block throws an exception, control would pass throw the associated finally block (if any) before the thread is terminated. 我知道在Java中,如果catch子句捕获了异常,并且其catch块引发了异常,则控制将在线程终止之前传递与关联的finally块(如果有)。 This does not appear to be the case in C#, however. 但是,在C#中似乎并非如此。
It is possible to almost mirror this behavior in C# is by putting a try-finally statement inside the try block of the try-catch statement with the catch block that throws the exception, but that would be a problem if, for example, the finally block is supposed to contain code that disposes a Stream Writer that is supposed to log the exception. 可以通过在try-catch语句的try块中放入try-finally语句和引发异常的catch块,来在C#中几乎反映出这种行为,但是,例如,如果finally块应该包含处理应该记录异常的Stream Writer的代码。
Is there a clean way to achieve java-like try-catch-finally exception handling behavior in C#? 有没有一种干净的方法来在C#中实现类似Java的try-catch-finally异常处理行为?
Here's an update with the requested sample code: 这是请求的示例代码的更新:
StreamWriter writer = new StreamWriter("C:\\log.txt");
try
{
throw new Exception();
}
catch (Exception e)
{
writer.WriteLine(e.Message);
throw e;
}
finally
{
if (writer != null)
{
writer.Dispose();
}
}
Add that code to a console application, run it, let the re-thrown exception go unhandled, attempt to delete C:\\log.txt. 将该代码添加到控制台应用程序中,运行它,让重新抛出的异常不被处理,尝试删除C:\\ log.txt。 You won't be able to, because control never passed through the finally block. 您将无法执行此操作,因为控制从未通过finally块。 Also, if you add a breakpoint to some line inside the finally block you will see that it doesn't get hit. 另外,如果在finally块内的某行上添加断点,您会发现它没有被命中。 (I'm using VS2005). (我正在使用VS2005)。
As far as I know, the only way to force control to pass through the finally block is if the re-thrown exception is handled by the catch block of an enclosing try block (if you took the code above and placed it inside the try block of another try-catch statement). 据我所知,强制控制通过finally块的唯一方法是重新引发的异常是否由封闭的try块的catch块处理(如果您将上面的代码放在了try块内)另一个try-catch语句的内容)。
If the exception is not caught and is allowed to terminate the application, as in the sample code I provided, control won't pass through the finally block. 如果未捕获到异常并允许其终止应用程序(如我提供的示例代码中所述),则控制将不会通过finally块。
In Java it would. 在Java中会。 In C#, at least based on what I have seen, it would not. 在C#中,至少基于我所见,它不会。
No, this is incorrect. 不,这是不正确的。 C# will always execute the finally
block, even after an exception is thrown/re-thrown from the catch
block. 即使从catch
块引发/重新抛出异常之后,C#仍将始终执行finally
块。 See When is finally run if you throw an exception from the catch block? 如果从catch块抛出异常,请参见何时最终运行? . 。
In the .NET Framework, when an exception occurs, the system will determine what if anything is going to catch that exception before any finally
blocks execute. 在.NET Framework中,当发生异常时,系统将确定在任何finally
块执行之前,是否有任何东西要捕获该异常。 Depending upon various application settings, an attempt to throw an exception which will not be caught may kill the application instantly, without giving any finally
blocks (or anything else) a chance to run. 根据各种应用程序设置,尝试抛出将不会被捕获的异常可能会立即杀死该应用程序,而不会给任何finally
块(或其他任何块)运行机会。
If one wraps the Main
method, as well as each thread, in 如果包装了Main
方法以及每个线程,
try
{
...
}
catch
{
throw;
}
then any exception which is thrown within the try
block will get caught. 那么任何在try
块中引发的异常都将被捕获。 Even though it will be immediately re-thrown, any nested finally
blocks will execute before the catch
. 即使立即将其重新抛出,任何嵌套的finally
块也将在catch
之前执行。 There are some cases where this is desirable behavior; 在某些情况下,这是理想的行为。 there are other cases where one may wish to eg perform some special logging if an exception isn't going to be caught (in some cases, the information one wishes to log may be destroyed if the finally
blocks get a chance to run first). 在其他情况下,如果不希望捕获异常,则可能希望执行一些特殊的日志记录(在某些情况下,如果finally
块有机会先运行,则希望记录的信息可能会被破坏)。 Within C#, there isn't any way to vary one's actions based upon whether an exception is going to be caught, but in VB.NET there are some ways via which that can be done; 在C#中,没有任何方法可以根据是否要捕获异常来改变一个人的动作,但是在VB.NET中,可以通过一些方法来完成。 a VB.NET assembly which makes calls to C# code can give that code a way of knowing whether any exceptions thrown by an inner method will propagate out to the vb.net wrapper without being caught. 调用C#代码的VB.NET程序集可以使该代码知道内部方法抛出的任何异常是否将传播到vb.net包装器而不会被捕获。
As already stated, the finally block will always run once the catch block has been executed. 如前所述,一旦执行catch块,finally块将始终运行。
Edit: I just tried the sample code provided by the OP in a console application and lo and behold, it did not hit the finally block and had an error of "An unhandled exception of type 'System.Exception' occurred in ConsoleApplication1.exe". 编辑:我只是尝试在控制台应用程序中运行由OP提供的示例代码,瞧瞧,它没有命中finally块,并且出现了错误“在ConsoleApplication1.exe中发生了'System.Exception'类型的未处理异常” 。 This was truly puzzling (besides the part of re-throwing the same exception in an endless loop) so I did a little investimagation and this is what I found: 这确实令人困惑(除了在无尽循环中重新抛出相同异常的部分之外),所以我做了一些研究,结果就是:
If a exception occurs the CLR traverses up the call stack looking for a matching catch expression. 如果发生异常,CLR将遍历调用堆栈以查找匹配的catch表达式。 If the CLR doen't finds a matching one, or the Exception gets re thrown each time, the Exception bubbles out of the Main() method. 如果CLR找不到匹配的CLR,或者每次都重新引发Exception,则Exception冒泡出Main()方法。 In that case Windows handles the Exception. 在这种情况下,Windows处理异常。
Event Handling of Console Applications is the easiest to understand, because there is no special Handling by the CLR. 控制台应用程序的事件处理最容易理解,因为CLR没有特殊的处理。 The Exception is leaving the Applications Thread if not caught. 如果未捕获,异常将离开应用程序线程。 The CLR opens a window asking for debug or exit the application. CLR将打开一个窗口,要求调试或退出应用程序。 If the user chooses to debug, the debugger starts. 如果用户选择调试,则调试器将启动。 If the user chooses to close, the Application exits and the Exception is serialized and written to the console. 如果用户选择关闭,则应用程序退出,并且异常被序列化并写入控制台。
Moral of the story, do not re-throw the same exception from a catch block in a console application!. 这个故事的寓意是,不要从控制台应用程序的catch块中再次抛出相同的异常!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.