简体   繁体   English

在C#中,如果关联的catch块引发异常,是否可以强制控制通过finally块?

[英]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包装器而不会被捕获。

This does not appear to be the case in C#, however. 但是,在C#中似乎并非如此。

Is this what you are looking for. 是您要找的东西吗?

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.

相关问题 在C#中传播在finally块中抛出的异常而不丢失catch块中的异常的最佳实践是什么? - What is the best practice in C# to propagate an exception thrown in a finally block without losing an exception from a catch block? C#异常处理最后在catch块之前阻塞 - C# exception handling finally block before catch block 在 catch/finally 块中抛出的吞咽异常 - Swallowing exception thrown in catch/finally block 为什么抛出的异常与catch块C#没有正确匹配 - Why thrown exception is not correctly matched with catch block C# 在finally块中引发异常 - Get thrown exception in finally block C# 异常处理 - 上次捕获块获取是否会重新抛出异常? - C# Exception Handling - will last catch block fetch re-thrown Exception? Selenium C# (NUnit) - 异常未在 catch 块中捕获,因为即使抛出异常也会执行 [onetimeteardown] - Selenium C# (NUnit)- Exception not caught in catch block as [onetimeteardown] executes even if exception thrown c# 中的 CATCH 块中的 GOTO 是否最终执行? - Does GOTO in CATCH block in c# execute FINALLY? 在C#中使用一个catch-all catch块的finally块是什么用的? - What's the use of a finally block preceded by a catch-all catch block, in C#? 在C#的Try块中,如果要在我的textbock中输入一个int,我想引发异常的catch部分吗? - In C# a Try block, the catch section i want a exception to be thrown if in my textbock a int is entered?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM