finally块中的多个操作

时间:2009-02-21 15:37:33

标签: c# exception

让我们说你有一些资源清理如下:这是C#。

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
 if( context.Transaction != null )
  context.Transaction.Dispose();
 context.Connection.Close();
 context.Connection.Dispose();
}

这样做会更健壮吗?

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
 try{
  if( context.Transaction != null )
   context.Transaction.Dispose();
 }catch(Exception e){/*logs*/}
 finally{
  context.Connection.Close();
  context.Connection.Dispose();
 }
}

这样,如果transaction.dispose在leat处设置失败,则连接将有机会关闭。

4 个答案:

答案 0 :(得分:12)

  

这样做会更健壮吗?

使用多个块会更好。

首先,你的catch块会吃掉所有异常并且不需要(可以试试......最后没有任何捕获)。如果你可以处理(或增加值)异常,只使用catch。

但更好:

using (var resA = GetMeAResourceNeedingCleanUp())
using (var resB = new AnotherResourceNeedingCleanUpn(...)) {
  // Code that might throw goes in here.
}

NB。一旦异常回退,最后块正在清理,抛出另一个异常可能会导致(充其量)混淆正在处理哪些异常。第二条准则:

不要从Dispose方法或终结器中抛出异常。如果您需要允许用户处理清理失败,请提供单独的Close方法,该方法可以报告其失败。

注意,“框架设计指南”(2 nd ed)将其作为(§9.4.1):

  

避免从Dispose(bool)中抛出异常,但在严重情况下除外   包含进程已损坏的情况(泄漏,不一致)   共享国家等。)。

答案 1 :(得分:3)

三点:

  • 您无需呼叫关闭以及处置
  • 在一个单独的finally块中处理事务是一个更好的主意,因为它可以防止在处理期间抛出异常。 (它不应该经常发生,但它可能会发生。)
  • using语句几乎总是处理资源的最简单方法。即使我想要一个try / catch块,我也会使用它,因为这是惯用的说法,“这使用了我希望在块的末尾处理的资源”

将这些结合起来将导致两个使用语句:

using (SqlConnection conn = ...)
{
    using (Transaction trans = ...)
    {
    }
}

如果您想避免过度缩进,可以将其写为:

using (SqlConnection conn = ...)
using (Transaction trans = ...)
{
}

答案 2 :(得分:0)

为什么Dispose调用会失败?你也可以在某些方面过于谨慎。就像用try / catch包装每个'new'语句一样,以防内存耗尽......

答案 3 :(得分:0)

我不喜欢我的最终条款太冗长(或任何条款,就此而言)。我会将您的资源清理重构为一些实用程序类。保留所有嵌套的try和“if null”条件,以便更好地重用。例如,因为清理逻辑只驻留在一个位置,所以稍后您可以轻松改变主意,确定是否确实需要调用Dispose()。

更重要的是,您的应用程序代码变得更易于理解。

try{/*stuff*/}
catch(Exception e) {/*rollback logs etc.*/}
finally{
  Utility.cleanup(context);
}