2013-10-08 21 views
0

我知道在Java中,如果一个异常被catch子句捕获,并且它的catch块引发异常,控制会在线程终止之前传递相关的finally块(如果有的话)。但是,这在C#中并不是这种情况。如果关联的catch块引发异常,是否可以强制控制通过finally块?

在C#中几乎可以反映这种行为是通过将try-catch语句放入try-catch语句的try块中,并使用catch块引发异常,但这会是一个问题,如果例如,finally块应该包含处理应该记录异常的Stream Writer的代码。

有没有一种干净的方式来实现类似于java的try-catch-finally异常处理行为在C#中?

下面是与所请求的样本代码的更新:

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(); 
    } 
} 

的代码添加到控制台应用程序,运行它,让我们重新抛出的异常走未处理的,试图删除C:\ log.txt的。你将无法执行,因为控制权永远不会通过finally块。另外,如果你在finally块的某行添加一个断点,你会发现它不会被触发。 (我正在使用VS2005)。

据我所知,强制控制通过finally块的唯一方法是,如果重新抛出的异常由封闭try块的catch块处理(如果你拿了上面的代码并放置它在另一个try-catch语句的try块内)。

如果没有捕获异常并且被允许终止应用程序,就像我提供的示例代码那样,控制将不会通过finally块。

在Java中它会。在C#中,至少基于我所看到的,它不会。

+2

他们都表现相同(至少如果我正确理解你的情况)。即使catch块抛出,相关的finally块也会被执行。如果你提供了示例代码,你的问题会更加清晰。 –

回答

1

在.NET Framework中,当发生异常时,系统将确定在执行任何finally块之前是否有什么东西会捕获该异常。根据不同的应用程序设置,试图抛出一个不会被捕获的异常可能会立即中断应用程序,而不会提供任何运行的块(或其他任何其他块)。

如果一个包裹Main方法,以及每个线程,在

try 
{ 
    ... 
} 
catch 
{ 
    throw; 
} 

然后是try块中抛出的任何异常都会被抓到。即使它会立即重新抛出,嵌套的finally块将在catch之前执行。有些情况下,这是理想的行为;在其他情况下,人们可能希望如果不会捕获异常,则执行一些特殊日志记录(在某些情况下,如果finally块有机会首先运行,那么希望记录的信息可能会被破坏)。在C#中,没有任何方法可以根据是否会捕获异常来改变一个人的行为,但在VB.NET中,有一些方法可以通过这些方法来完成;一个调用C#代码的VB.NET程序集可以让代码了解内部方法抛出的任何异常是否会传播到vb.net包装而不被捕获。

+0

你的解释与我观察到的行为一致。这是否在.NET Framework的规范中?另外,您提到的应用程序设置是什么以及它们如何配置? –

+0

@JSmith:我已阅读过一些设置,但遗憾的是不记得细节。 ECMA规范明确规定了发现异常未处理的情况;在此之后,实施可能(就规范而言)做它喜欢的事情,IIRC。 – supercat

0

但是,这在C#中似乎不是这种情况。

this你在找什么?

0

如前所述,finally代码块将在catch代码块执行后一直运行。

编辑:我刚刚在控制台应用程序中尝试了OP提供的示例代码,并且看到它没有触及finally块,并且出现错误“未处理的类型为'System.Exception'的异常发生在ConsoleApplication1.exe中”。这确实令人费解(除了重新抛出同样的异常在一个无限循环的一部分),所以我做了一个小investimagation,这是我发现:

如果出现异常的CLR遍历调用堆栈寻找匹配catch表达式的 。如果CLR找不到匹配的,则每次都会抛出 或异常,异常会冒出Main()方法的 。在这种情况下,Windows会处理异常。

事件处理控制台应用程序是最容易理解的, ,因为CLR没有特殊的处理。例外是 如果未捕获应用程序线程将保留。 CLR打开一个窗口 询问调试或退出应用程序。如果用户选择 调试,则调试器启动。如果用户选择关闭, 应用程序将退出并且异常被序列化并写入 控制台。

道德故事,不要在控制台应用程序中从catch块中重新抛出相同的异常!

+0

“如前所述,finally代码块将在catch代码块执行后始终运行。”根据规范,这可能是正确的,但在实践中似乎并不总是如此。 –

+0

@J Smith更新了答案。 – JuStDaN

相关问题