28

这是“throw”和“throw ex”之间有区别</a>的后续问题吗?

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

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

4

5 回答 5

54

在 .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.
    }
}
于 2012-09-27T10:16:09.493 回答
49

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

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

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

于 2009-04-08T14:34:32.943 回答
31

不知道你是不是这个意思,但我在你的另一个问题中的建议是解决这个问题。

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

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}
于 2009-04-08T14:36:09.943 回答
5

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

但是,您可以将原始异常作为“InnerException”放入新异常中。那会做你正在寻找的吗?

于 2009-04-08T14:35:42.753 回答
3

您是否捕获了想要更仔细过滤的异常,以便您可以改变主意,决定不处理它们并重新抛出它们?

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

这意味着(在 C# 中)您必须仔细catch为要捕获的所有异常类型编写一个单独的处理程序。这也意味着您只能按异常类型进行过滤。这有时是很难遵循的建议。

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

这是来自 CLR 团队博客的详细解释,带有 VB.NET 代码示例。

这是我的两分钱。

于 2009-04-08T14:50:49.830 回答