C#重新抛出异常:如何在IDE中获取异常堆栈?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#重新抛出异常:如何在IDE中获取异常堆栈?相关的知识,希望对你有一定的参考价值。

之前有关于重新抛出异常的正确方法的讨论。相反,这个问题是关于如何在使用rethrow时从Visual Studio获得有用的行为。

考虑以下代码:

   static void foo() {
        throw new Exception("boo!");
    }

    static void Main(string[] args) {
        try {
            foo();
        } catch (Exception x) {
            // do some stuff
            throw;
        }
    }

出现的异常具有正确的堆栈跟踪,显示foo()作为异常的来源。但是,GUI调用堆栈窗口只显示Main,而我期望它显示异常的调用堆栈,一直到foo。

当没有重新抛出时,我可以使用GUI快速导航调用堆栈,以查看导致异常的调用以及我们如何到达那里。

通过重新抛出,我希望能够做同样的事情。相反,GUI显示的调用堆栈对我没用。我必须将异常详细信息复制到剪贴板,将其粘贴到记事本,然后手动导航到我感兴趣的调用堆栈的任何功能。

顺便说一句,如果我添加[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]或者如果我将捕获更改为catch (Exception),我会得到相同的行为。

我的问题是:鉴于我使用的代码重新抛出,有人可以建议一种方便的方法来导航与异常相关的调用堆栈吗?我正在使用Visual Studio 2010。

答案

调试器在throwMain中断,因为该异常未处理。默认情况下,调试器只会中断未处理的异常。一旦你停在Mainfoo的原始异常的调用堆栈就会出现在异常中,但是所有其他的上下文都已丢失(例如本地,堆栈/内存状态)。

听起来你希望调试器在throw中的foo中断,所以你应该告诉调试器打破第一次机会异常:

  1. 调试»例外...(Ctrl + Alt + E)
  2. 检查“Thrown”以查找您关心的异常类型(在本例中为Commange Language Runtime Exceptions)
  3. 单击确定
  4. 开始调试

在这种情况下,当foo抛出异常时,调试器将立即中断。现在,您可以在原始异常的上下文中检查堆栈,本地等。如果继续执行(F5),调试器将在Main中的重新抛出时再次中断。

采用另一种方法,如果您正在运行VS2010 Ultimate,您还可以使用IntelliTrace“向后调试”以查看异常时的参数,线程和变量。有关详细信息,请参阅this MSDN article。 (完全披露:我在与IntelliTrace密切相关的团队工作)。

另一答案

如果使用ReSharper,则可以将异常堆栈跟踪复制到剪贴板,然后在菜单中选择:ReSharper>工具>浏览堆栈跟踪(Ctrl + E,T)。它将显示具有可点击位置的堆栈跟踪,因此您将能够快速导航。

http://www.jetbrains.com/resharper/webhelp/images/Reference__Windows__Stack_Trace_Explorer.png

在挖掘用户的日志时(如果记录了异常的堆栈跟踪),此功能也非常有用。

另一答案

不是你应该重新抛出,但here是一篇关于如何保留堆栈跟踪的博客文章,基本上归结为:

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

...
catch (Exception ex)
{
  // do something
  // ...
  PreserveStackTrace(ex);
  throw;
}
另一答案

Mike Stall为你的问题提供了great and simple solution

使用属性[DebuggerNonUserCode]标记重新抛出异常的方法

IDE会认为这不是您的代码,并且不会在这样的地方破坏调试器,而是会在堆栈中进一步查看,显示下一个重新抛出或初始异常位置。

(如果下一次重新抛出也很烦人,也将它标记为[DebuggerNonUserCode]等等......)

以上是关于C#重新抛出异常:如何在IDE中获取异常堆栈?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Javascript 中重新抛出异常,但保留堆栈?

抛出异常时如何获取 JavaScript 堆栈跟踪?

如何在 C# 中重新抛出 InnerException 而不会丢失堆栈跟踪?

在不丢失堆栈跟踪的情况下重新抛出 Java 中的异常

使用 sbt 和 testng 时,如何获取测试中抛出的异常的完整堆栈跟踪?

捕获和重新抛出 .NET 异常的最佳实践