尝试/最后(没有Catch)冒泡异常吗?

Set*_*man 105 .net c# vb.net exception-handling

我几乎肯定答案是肯定的.如果我使用Try Finally块但不使用Catch块,那么任何异常都会冒泡.正确?

一般的做法有什么想法吗?

赛斯

Jon*_*eet 119

是的,绝对会.假设你的finally块没有抛出异常,当然,在这种情况下,它将有效地"替换"最初抛出的异常.

  • @David:你不能从C#中的finally块返回. (13认同)
  • [msdn documentation](http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx)也确认了这个答案:_或者,您可以捕获可能在try-finally的try块中抛出的异常语句高出调用堆栈.也就是说,您可以在调用包含try-finally语句的方法的方法中,或在调用该方法的方法中或在调用堆栈的任何方法中捕获异常.如果未捕获异常,则执行finally块取决于操作系统是否选择触发异常展开操作._ (3认同)

Eri*_*ert 57

一般的做法有什么想法吗?

是.要小心.当您的finally块正在运行时,它完全可能正在运行,因为已经抛出了未处理的意外异常.这意味着某些东西被打破了,一些完全出乎意料的事情可能会发生.

在那种情况下,可以说你不应该在finally块中运行代码.finally块中的代码可以构建为假设它所依赖的子系统是健康的,而实际上它们可能会被彻底破坏.finally块中的代码可能会使事情变得更糟.

例如,我经常看到这样的事情:

DisableAccessToTheResource();
try
{
    DoSomethingToTheResource();
}
finally
{
    EnableAccessToTheResource();
}
Run Code Online (Sandbox Code Playgroud)

这段代码的作者正在思考"我正在对世界状态进行临时变异;我需要将状态恢复到我被召唤之前的状态".但是让我们考虑一下这可能出错的所有方法.

首先,调用者已经可以禁止访问资源; 在这种情况下,此代码可能会过早地重新启用它.

其次,如果DoSomethingToTheResource抛出异常,那么启用对资源的访问是正确的做法吗?管理资源的代码意外中断.这段代码说,实际上"如果管理代码被破坏,请确保其他代码可以尽快调用那些损坏的代码,这样它也可能会失败." 这似乎是一个坏主意.

第三,如果DoSomethingToTheResource抛出异常,那么我们怎么知道EnableAccessToTheResource也不会抛出异常?无论可怕的是什么,资源的使用也可能影响清理代码,在这种情况下原始异常将丢失并且问题将更难以诊断.

我倾向于在不使用try-finally块的情况下编写这样的代码:

bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
    DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
    EnableAccessToTheResource();
Run Code Online (Sandbox Code Playgroud)

现在除非需要,否则状态不会发生变异.现在呼叫者的状态并没有被搞乱.现在,如果DoSomethingToTheResource失败,那么我们就不会重新启用访问权限.我们假设某些事情已经被彻底打破,并且不会冒险通过尝试继续运行代码来使情况变得更糟.如果可以,让呼叫者处理问题.

那么什么时候运行finally块是个好主意?首先,当预期异常时.例如,您可能希望锁定文件的尝试可能会失败,因为其他人已将其锁定.在这种情况下,捕获异常并将其报告给用户是有意义的.在这种情况下,减少了什么被打破的不确定性; 你不太可能通过清理让事情变得更糟.

其次,当您正在清理的资源是稀缺的系统资源时.例如,关闭finally块中的文件句柄是有意义的.("使用"当然只是编写try-finally块的另一种方式.)文件的内容可能已损坏,但现在你无能为力.文件句柄最终将被关闭,因此它可能更快而不是更晚.

  • 还有更多的例子说明我们如何在错误处理方面将我们的行为放在一起作为一个行业.并不是说我有更好的建议而不是例外,但我希望未来能够更有可能导致合理容易地采取正确的行动方案. (5认同)
  • 埃里克,谢谢你的回答.我想我应该问两个问题,因为你和Jon都是正确的.在任何情况下,你都被投票赞成.感谢您关注这个问题. (2认同)