JUST在捕获中“抛出”是否有益处?

时间:2008-10-20 15:16:01

标签: c# .net vb.net

与一位同事进行了激烈的辩论,讨论了他在try / catch中包装大部分功能的做法,但抓住了它只是“抛出”,例如。

Private sub foo()
    try
        'Do something'
    catch
        throw 'And nothing else!'
    End Try
End Sub

我的想法是甚至不打扰(假设您此时不需要做任何事情) - 异常会冒泡到父成员中的下一个异常处理程序。

听起来似乎有道理的唯一论点是,有时异常未被捕获且您的代码停止(在调试模式下),当前行以绿色突出显示...并且这可能与多个线程有关? 最佳实践会声明“每个线程的异常处理程序”,但主要是我们使用单线程。

好处可能是它在调试模式下可能有用而不会突然弹出到父成员(是的,Joel!) - 你将转到“throw”语句并能够检查你的本地人。 但是那时你的代码会“乱七八糟地尝试/捕获/抛出”(在这里引用另一个线程)?

如果没有异常发生,那么在任何地方添加try / catch / throws会涉及什么样的开销(即你应该避免在紧密循环中尝试/捕获)?

11 个答案:

答案 0 :(得分:18)

Microsoft建议您不要捕获异常,因为您唯一要做的就是立即重新抛出异常(我现在不记得源代码)。 您的代码应该只捕获您想要处理的异常事务或类似操作。

因此,一般来说捕获和重新抛出异常并不是一个好习惯。

使用其他例外捕获和替换它的原因可能是

  • 登录
  • 隐藏来自调用者的敏感信息(Stacktrace,异常详情)

对于调试,您可能希望更改“异常时为中断:” - 处理程序(按Ctrl + Alt + e)选中的CLR例外值“抛出”。

您可能希望查看entlib异常处理程序块(EHB),使用该块可以建立关于如何处理代码中的异常的模式。

关于你的性能问题,我认为在你的代码中有很多try / catch块并不是一个问题,但是当你的代码引发并捕获许多异常时你会得到性能命中。

答案 1 :(得分:17)

你在catch中单独抛出而不是抛出新异常的原因是因为这会导致保留原始堆栈跟踪/异常数据。你可能会这样做的一个原因是因为你现在可以设置一个断点来进行调试。

答案 2 :(得分:8)

我只会在调试问题时执行此操作 - 并且在签入之前我会再次删除代码。如果抛出异常,有时可以放置一个断点来停止特定的堆栈级别。除此之外 - 没有。

答案 3 :(得分:6)

在实践中,我的想法是,如果您不打算处理错误,请不要抓住它。

答案 4 :(得分:2)

使用catch和立即重新抛出的一个好处是任何内部“Finally”块都将在“Catch”发生之前运行(这将在异常传播之前进行)。这与两种情况相关:

  1. 如果最终未处理异常,则未处理的异常陷阱可能会退出应用程序而不运行任何“finally”块。捕获并立即重新抛出将确保catch中的所有“finally”块都将执行,即使异常最终未被处理也是如此。
  2. 在运行任何finally块之前,vb.net中的代码以及可能的其他语言可能会对异常起作用。使用带有catch-and-immediate-rethrow的“try”块将导致该catch块中的“finally”块在任何外部“try”块首次查看异常之前运行。

使用catch-and-immediate-rethrow的另一个警告:由于某种原因,catch和立即重新抛出将废弃导致异常的函数调用的堆栈跟踪的行号。我不知道为什么在这种情况下,当前函数在堆栈跟踪中的条目不能单独存在,但事实并非如此。如果没有使用.pdb文件来获取行号信息,这不是问题,但如果想要使用这些信息,则可能会令人讨厌。

通常,上述效果是不可取的,但有时前两种效果中的一种或两种可能有用,第三种效果可以容忍。在这些情况下,立即重新捕获的捕获量可能是合适的,但应记录其原因。

答案 5 :(得分:1)

默认情况下总是这样做看起来很糟糕。但是可能有捕捉和投掷的理由,例如你想抛出一个不同的例外。

答案 6 :(得分:1)

是的,在捕获中放置一个断点很方便。

替代且更清洁的方式是您要投掷的对象的构造函数中的断点。您在更接近错误源的位置看到程序状态。

答案 7 :(得分:1)

需要一个catch子句来捕获Visual Studio调试器中的异常。选择Debug>例外情况,并根据需要选择要捕获的异常。

答案 8 :(得分:1)

如果捕获异常并将其替换为另一个异常,则通常应将原始异常包装在新异常中。这通常是通过将旧异常传递给新的构造函数来完成的。这样你就可以尽可能地挖掘出来,弄清楚发生了什么。当您不需要隐藏数据时出于安全原因,主要情况就是这样。在这些情况下,您应该在清除之前尝试记录异常数据。

我所看到的用新的包装异常而不仅仅是让它们冒出堆栈的原理是,异常应该与它们来自的方法处于相同的语义级别。如果我调用AuthenticateUser,我不希望看到SQL异常。相反,我应该看到一些异常,其名称告诉我无法完成身份验证任务。如果我深入研究这个异常的内部异常,我就可以找到SQL异常。就个人而言,我仍在权衡这样做的利弊。

答案 9 :(得分:0)

由于没有错误处理,这个捕获是没用的。如果确实有记录或清理,但在这种情况下我会摆脱try / catch。

答案 10 :(得分:0)

如果您需要检查有关异常的内容,并针对某种情况执行某些操作或将其投入其他情况,这也很有用。例如,如果需要在SQLException中检查错误号。如果错误编号是您准备处理的错误编号,则可以执行某个操作。对于其他人,您可以简单地“抛出”它,以便保留堆栈跟踪,如上所述。