如何在不重置堆栈跟踪的情况下抛出异常?

时间:2009-04-08 14:32:45

标签: c# .net exception-handling error-handling stack-trace

这是Is there a difference between “throw” and “throw ex”的后续问题?

有没有办法在不重置堆栈跟踪的情况下提取新的错误处理方法?

[编辑] 我将尝试“内部方法”和Earwicker提供的另一个answer,看看哪一个可以更好地标记答案。

5 个答案:

答案 0 :(得分:43)

是;这就是InnerException属性的用途。

catch(Exception ex)
{
    throw new YourExceptionClass("message", ex);
}

这将允许您添加自己的逻辑,然后抛出自己的异常类。 YourExceptionClass实例的StackTrace将来自此代码块,但InnerException将是您捕获的异常,使用之前的StackTrace。

答案 1 :(得分:39)

使用.NET Framework 4.5,现在有ExceptionDispatchInfo支持这种确切的方案。它允许捕获完整的异常并从其他地方重新抛出它而不会覆盖包含的堆栈跟踪。

由于评论请求而导致的代码示例

using System.Runtime.ExceptionServices;

class Test
{
    private ExceptionDispatchInfo _exInfo;

    public void DeleteNoThrow(string path)
    {
        try { File.Delete(path); }
        catch(IOException ex)
        {
            // Capture exception (including stack trace) for later rethrow.
            _exInfo = ExceptionDispatchInfo.Capture(ex);
        }
    }

    public Exception GetFailure()
    {
        // You can access the captured exception without rethrowing.
        return _exInfo != null ? _exInfo.SourceException : null;
    }

    public void ThrowIfFailed()
    {
        // This will rethrow the exception including the stack trace of the
        // original DeleteNoThrow call.
        _exInfo.Throw();

        // Contrast with 'throw GetFailure()' which rethrows the exception but
        // overwrites the stack trace to the current caller of ThrowIfFailed.
    }
}

答案 2 :(得分:26)

不确定你的意思是,但我在你的另一个问题中提出的建议是解决这个问题。

如果你的处理程序返回一个布尔值,无论是否处理了异常,你可以在catch子句中使用它:

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}

答案 3 :(得分:5)

您不希望使用原始堆栈跟踪创建新异常。这是误导性的,因为堆栈跟踪没有创建新的异常。

但是,您可以将原始异常作为“InnerException”放在新异常中。这会做你想要的吗?

答案 4 :(得分:2)

你是否正在捕捉你想要过滤的异常,然后你可以改变主意,决定不处理它们,然后重新抛出它们?

如果你想对此非常小心,那不是一个好主意。最好永远不要抓住异常。原因是给定的try/catch处理程序不应该决定为不期望看到的异常运行嵌套的finally块。例如,如果存在NullReferenceException,则继续执行任何代码可能是一个非常糟糕的主意,因为它可能会导致抛出另一个此类异常。 finally块只是代码,就像任何其他代码一样。一旦第一次捕获到异常,finally下面的堆栈上的任何try/catch块都将被执行,到时为止已经太晚了 - 可能会生成另一个异常,这意味着原来的例外遗失了。

这意味着(在C​​#中)你必须小心地为你想要捕获的所有异常类型写出一个单独的catch处理程序。它还意味着您只能按例外类型进行过滤。这有时是非常难以遵循的建议。

应该可以通过其他方式过滤异常,但在C#中则不是。但是,它可以在VB.NET中使用,并且BCL本身通过使用VB.NET编写的少量代码来利用这一点,因此它可以以更方便的方式过滤异常。

Here's a detailed explanation, with a VB.NET code sample, from the CLR team blog.

And here's my two cents.