C#中的异常传播

时间:2010-12-08 19:17:53

标签: c# exception-handling

假设我在C#程序中有三个函数doA(),doB()和doC(),我知道doA()将调用doB(),而doB()又调用doC()。

由于doC()必须与数据库进行交互,因此我知道它很可能会生成无法解决的异常需要引起用户注意。目前,我有一些代码可能会在doC()中的try / catch打击中抛出错误,然后在另一个try / catch中调用doB()中的doC(),同样在doA中调用doB() ()在try / catch块中。这允许我只使用throw;将异常踢到doA(),在那里可以合理地将某些内容显示给用户。

这看起来有点像矫枉过正。我想知道是否因为我不打算在doB()或doC()中处理异常,如果我可以摆脱那里的try / catch块。

假设没有涉及最终块,处理这种情况的最佳做法是什么?

7 个答案:

答案 0 :(得分:10)

如果你的阻止块是这样的:

catch (Exception)
{
    throw;
}
然后他们确实毫无意义。你并没有真正处理这个例外 - 根本不需要尝试使用try / catch。

就我个人而言,我的代码中只有很少的try / catch块 - 虽然有很多隐含的 try / finally块,但大多数是由using语句引起的。

答案 1 :(得分:5)

是的,我会摆脱try / catch块 - 只是让异常传播到顶层,然后在那里捕获它。仅仅为了重新抛出throw;来捕获异常是没有用的,尽管以下变体实际上是有害的,因为它会破坏堆栈跟踪信息:

catch (Exception exception)
{
    throw exception;
}

答案 2 :(得分:5)

如果您打算做某事(或者试图阻止传播),您只需要抓住。如果你没有捕获,它会进入调用者的捕获。在你的情况下,似乎doA()(或者可能是它的调用者,取决于你可以处理它的位置)是唯一需要try / catch的函数。

答案 3 :(得分:2)

异常冒泡调用堆栈。

如果发生异常的方法没有处理它,则调用者获取它的方法。如果调用者没有处理它,它会进一步向上调用堆栈,直到框架处理它并崩溃你的应用程序。

回答你的问题:在你的情况下没有必要重新抛出异常。

答案 4 :(得分:0)

恕我直言,应该尽可能少地抓住一个例外,实际上这是一个相当昂贵的操作来捕捉异常。

案例可能会出现在您跨越应用程序层的地方,并且可能需要一个层来记录/重新抛出,而下一层也需要捕获它。但在你的情况下,它只是一层,所以我会说在调用堆栈的最高位置,你可以用异常做一些事情,记录它并做你的业务逻辑。

答案 5 :(得分:0)

简而言之,你的问题的答案是肯定的。捕获异常的唯一原因是使用它做一些事情。如果你不能在DoC()中做任何有用的事情,那就让它冒泡吧。

在代码的入口点尝试捕获块(通常在win窗体应用程序中的事件处理程序中),这是一个很好的做法,这样就没有任何东西可以被捕获。那时你可以用它来告诉用户。

但是,如果他们可以采取合理的行动,您可能还希望适当地放置一些较低级别的处理程序。例如,在doC()中,您可能希望捕获与死锁和重试有关的异常。在某种程度上,您可能还希望捕获约束错误并在其位置引发更有意义的用户目标错误。我有blog post about that here

答案 6 :(得分:0)

你要捕获的异常类型在每个级别都可能不同,我不确定你在3个级别做了什么,但是在堆栈的顶部你只能有1种类型的异常,在较低级别那里可能是不同类型的异常,这有点迫使您使用广泛的异常类型,然后使用特定的异常类型,其中可能没有明确的信息。

所以这取决于你要抛出的例外类型。