是否有任何技术原因要编写仅包含throw语句的catch块?

时间:2017-10-09 09:24:50

标签: c# exception-handling

免责声明:众所周知try { ... } catch { throw; } is bad practice。这个问题

在挖掘Microsoft参考资源时,我注意到a lot of methods中的以下模式:

catch { throw; }

没有记录,没有调试代码 - 只是简单的try-finally

显然,微软的人应该相当熟练使用C#,这样做的重点是什么,而不是仅仅省略catch块(和try语句)? 这样的编码有技术原因,还是纯粹的风格选择?

注意:我不知道它是否相关,但是我能找到的所有这些实例都包含嵌套在try子句内的try-catch块{1}}阻止。

3 个答案:

答案 0 :(得分:12)

它会影响异常过滤器的运行时间。

鉴于

void f() {
  using (var x = AcquireResource()) {
    x.DoSomething();
    x.DoSomethingElse();
  }
}

void f() {
  try {
    using (var x = AcquireResource()) {
      x.DoSomething();
      x.DoSomethingElse();
    }
  } catch {
    throw;
  }
}

void g() {
  try {
    f();
  } catch (Exception ex) when (h()) {
    // ...
  }
}

f的第一个版本允许在h()处置之前调用过滤器xf的第二个版本可确保在运行外部代码之前处置x

在您链接到的代码中,SqlConnectionHolder被大量使用,catch { throw; }块围绕SqlConnectionHolder使用。

答案 1 :(得分:7)

正如C# Specification所述:

  

发生异常时,系统会搜索最近的catch子句,该子句可以处理异常,由异常的运行时类型决定。首先,在当前方法中搜索词法封闭的try语句,并按顺序考虑catch语句的关联try子句。如果失败,则搜索调用当前方法的方法,以查找包含对当前方法的调用点的词法封闭try语句。此搜索将继续,直到找到可以处理当前异常的catch子句,方法是命名与抛出的异常的运行时类型相同的类或基类的异常类。没有命名异常类的catch子句可以处理任何异常。

     

一旦找到匹配的catch子句,系统就会准备将控制转移到catch子句的第一个语句。在开始执行catch子句之前,系统首先按顺序执行与finally语句相关联的任何try子句,这些子句比捕获异常的语句更嵌套。

在异常运行时首先查找可以处理它的catch子句,其中涉及执行任何关联的异常过滤器。不加区别的catch阻止中断,搜索并立即执行所有嵌套finally块。

当您想要阻止调用者在finally阻止之前执行任意代码(以异常过滤器的形式)时,这可能很有用。例如,当finally块影响当前线程的安全上下文时。

此外,如果任何catch子句都不会捕获异常,那么它将导致线程终止。在这种情况下,C#规范没有提供任何保证,任何finally块都将被执行。

  

如果搜索匹配的catch子句到达最初启动该线程的代码,则终止执行该线程。这种终止的影响是实现定义的。

答案 2 :(得分:-2)

您链接的代码实际上是一个很好的例子。

在我看来,在处理他们无法控制的事情时,应该只使用 try catch 块,比如文件系统,外部事物。

在您链接的代码中, try catch 是围绕数据库的东西。

这意味着通过使用这种编码方式,他们确保没有泄漏,没有连接保持打开状态。

如果出现任何问题,例如错误的连接字符串,缺少表,等等,代码将继续执行,它将正常关闭连接,如 finally 块中所示,它将最后抛出意味着它将允许该代码的客户端获得正确的异常,同时获取整个堆栈并让他们决定在发生这种情况时该怎么做。

说实话,我非常喜欢他们在那里所做的事。