2

我在学习过程中的某个地方遇到了这部分代码。我在这里发现一个观察结果,即使作者使用“using”块并创建“ts”对象,他在 using 块中使用 try catch 块,在 catch 部分中,他显式调用 Dispose 方法处理对象“ts” . 我觉得没必要。如果他必须“只处理对象”,我不明白为什么他需要在这里尝试并抓住。

我的问题:

  1. 我们真的需要 try catch 吗?在什么情况下,它将在此示例中发挥作用?

  2. 使用“使用”块时这种方式正确吗?它在 GC 过程中如何反应?它的开销对吗?

欣赏这两个问题是否可以以初学者可以理解的方式解释。

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    try
    {
        ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client();
        obj.UpdateData();
        ServiceReference2.Service1Client obj1 = new ServiceReference2.Service1Client();
        obj1.UpdateData();
        ts.Complete();
    }
    catch (Exception ex)
    {
        ts.Dispose();
    }
}
4

11 回答 11

5

这对我来说确实似乎没有必要。该using语句将编译为finally包装整个代码块的块,无论是否引发异常,该块都将执行。

本质上,他正在写这个:

TransactionScope ts;
try
{
    ts = new TransactionScope(TransactionScopeOption.RequiresNew);
    try
    {
        ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client();
        obj.UpdateData();
        ServiceReference2.Service1Client obj1 = new ServiceReference2.Service1Client();
        obj1.UpdateData();
        ts.Complete();
    }
    catch (Exception ex)
    {
        ts.Dispose();
    }
}
finally
{
    ts.Dispose();
}

这有点愚蠢。尤其愚蠢的是,他完全无视(或“吞下”)例外。99.99999993% 的时间,这是个坏主意。

于 2013-03-01T20:03:27.987 回答
1

在这个特定的代码片段中,catch 子句唯一做的就是防止异常冒泡。实际上,它忽略了异常。

这里的 dispose 方法用于回滚事务,但是由于一旦代码在 using 块之外,无论如何都会调用 dispose ,因此它仍然是不必要的。

于 2013-03-01T20:02:56.157 回答
1
  1. 不,你不需要这里的渔获物。
  2. 通过“这种方式”,我假设您不是指此处的 try/catch 块实现的双重处置。是的,这是正确的方法(丢失 try/catch 部分)。

当代码离开代码using块时,ts这里有问题的对象将被处理掉。您的程序可以在不释放对象的情况下离开此块的唯一方法是:

  1. 杀死程序
  2. 终止线程

因此,您不需要 try/catch 部分来正确处理对象。

然而, try/catch 代码的作用是吞下 try 块中代码中的任何异常。然而, dispose 调用是不必要的。

于 2013-03-01T20:03:52.850 回答
1

据我了解,没有理由Dispose打电话。然而,有理由try catch。例如,如果UpdateData呼叫失败,您可能需要进行一些调整,然后重试。您可能还希望以不同的方式处理不同的异常,如果没有 catch 块,您将没有任何机会这样做。

于 2013-03-01T20:03:53.250 回答
1

无论如何使用“使用”时,都会在 finally 部分隐式调用 ts.Dispose。但是,如果您没有捕获异常,它将被抛出,在您的示例中,异常被 catch 块默默地吞噬。

于 2013-03-01T20:04:13.383 回答
1

使用语句

using 语句可确保调用 Dispose,即使在调用对象上的方法时发生异常也是如此。您可以通过将对象放在 try 块中,然后在 finally 块中调用 Dispose 来获得相同的结果;事实上,这就是编译器翻译 using 语句的方式。

所以是的,在您发布的代码中的异常块中进行处理是不必要的。

于 2013-03-01T20:04:22.060 回答
1

通过定义的任何对象都using必须实现IDisposable。该对象Disposed()一旦超出范围(意味着控制离开using块),无论以何种方式——return语句、a goto、异常等。因此捕获异常以确保using变量被正确处理是多余的。

这段代码:

using ( MyDisposableObject x = new MyDisposableObject() )
using ( AnotherDisposableObject y = new AnotherDisposableObject() )
{
  x.Foo() ;
  y.Bar( x ) ;
}

与此代码完全相同:

MyDisposableObject x = new MyDisposableObject() ;
AnotherDisposableObject y = new AnotherDisposableObject() ;
try
{
  x.Foo() ;
  y.Bar( x ) ;
}
finally
{
  x.Dispose() ;
  y.Dispose() ;
}

但是,有一些原因,您可能希望在using块中捕获异常。其中:

  • 实际处理捕获的异常。
  • 记录并重新抛出捕获的异常。
  • 例如,故意吞下特定异常以允许执行继续。您可能想要这样做的原因包括,例如,要求获得权限以查看您是否被允许做某事。如果请求失败,则会引发 SecurityException。捕获允许您采取行动,例如,通知用户他们没有打开他们要求的文件的权限。
于 2013-03-01T20:08:43.867 回答
1

简短的回答是否定的。TransactionScope 实现了 IDiposable,因此 C# using 语句将在执行代码块后自动调用 Dispose()。

在这种情况下,try/catch 块的用处是可能完成某些类型异常的事务。

在大多数情况下,只需调用 ts.Complete(); 就足够了。作为 using 块中的最后一条语句。这确保了之前抛出的任何异常都会导致事务回滚。

于 2013-03-01T20:10:27.690 回答
0

您无需在 using 语句中调用 Dispose。它为您处理。

如果您想在那里处理一些异常,那么在 using 中使用 try catch 没有任何问题,只是不要进行处置。

于 2013-03-01T20:03:44.403 回答
0

不,那个特别try..catch是完全没用的(好吧,无论如何,它确实会默默地吃掉你可能遇到的任何异常)。

请注意,这不是等价的,该using子句更强大,因为它甚至会调用Dispose成功,因为它扩展为 atry..finally而不仅仅是 a try..catch

于 2013-03-01T20:03:44.550 回答
0

1)如果您要真正处理异常或记录并再次抛出它,您只需要try/catch。try/catch 的任何其他用途都是不好的做法。在这种情况下,你要做的就是 dispose ts,所以你不需要它,因为你在一个using块内。

2)不,您不需要调用 dispose:即使有异常,使用块也会处理它。

于 2013-03-01T20:05:14.337 回答