【问题标题】:Exceptions lose part of stacktrace in try/catch context异常会在 try/catch 上下文中丢失部分堆栈跟踪
【发布时间】:2014-08-09 11:00:20
【问题描述】:

我有两个例子。在第一种情况下,调试器捕获未处理的异常:

static void Main(string[] args) {
    Exec();
}
static void Exec() {
    throw new Exception();
}

并且异常具有完整的堆栈跟踪:

   at ConsoleApplication28.Program.Exec() 
   at ConsoleApplication28.Program.Main(String[] args) 
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

第二种情况:

static void Main(string[] args) {
    Exec();
}
static void Exec() {
    try {
        throw new Exception();
    }
    catch (Exception ex) {
    } // Breakpoint
}

在断点处,异常的堆栈跟踪很短:

   at ConsoleApplication28.Program.Exec()

为什么在第二种情况下stacktraces被切到包含方法,以及如何防止它?我需要完整的堆栈跟踪来获取错误报告,否则有时无法在没有完整堆栈跟踪的情况下找到问题所在。

【问题讨论】:

  • “我需要完整的堆栈跟踪来获取错误报告,否则有时在没有完整堆栈跟踪的情况下无法找到问题所在。”要回答您问题的这一部分,您需要在 Main() 方法中可能发生异常的“上方”某处插入一个 try-catch 结构,可能就在顶部。在 catch 子句中,您应该将 exceptionObject.ToString() 写入某个文件或其他内容以供以后分析。

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


【解决方案1】:

您在 Visual Studio 调试器中看到的是 Visual Studio 托管进程正在捕获的未处理异常(即前两个堆栈帧之后的所有内容都是 VS“主机管道”的一部分)。如果禁用托管进程(项目属性->启用 Visual Studio 托管进程),您将在两种情况下看到“短”堆栈跟踪(尽管在第二种情况下您不会看到 Main 的堆栈帧因为异常是“处理的”,不允许传播到Main)。这个较短的堆栈跟踪是您在调试器之外运行应用程序时会看到的堆栈跟踪。

堆栈的工作方式与您想象的一样 - 每个方法调用都会将另一个堆栈帧推入它,并且在方法结束时,它的堆栈帧被“弹出”或从堆栈中删除。您在异常上看到的堆栈跟踪由从引发异常的帧到最终处理异常的帧的堆栈帧组成,因为堆栈是“展开”的。

【讨论】:

  • 您可能需要重新组织此答案,以更清楚地指示堆栈跟踪的哪一部分是由于托管进程而哪一部分是由于 catch 块。然后,您可以强调堆栈跟踪是在异常遍历堆栈级别时聚合的,因此 Main 部分根本不存在。
  • 但是为什么 Main() 不在第二个堆栈跟踪中?我不明白。我通过 System.Diagnostics.StackTrace 和 Main() 检查了异常点的堆栈跟踪。
  • 异常堆栈跟踪是直到捕获异常为止的堆栈跟踪。该堆栈跟踪随着异常在调用堆栈的级别上冒泡而增长。它显示“迄今为止的堆栈跟踪是什么”,而不是“回到程序开头的调用堆栈是什么”。
【解决方案2】:

如果您需要完整的堆栈跟踪,您可以使用:

catch(Exception ex)
{
    var log = ex.ToString() + Environment.NewLine + new System.Diagnostics.StackTrace(true);
}

您可能会得到比您需要的更长的跟踪。要获得更短的跟踪,您可以使用:

var NL = Environment.NewLine;
var stack = new StackTrace(true).ToString().Split(new[] { NL }, StringSplitOptions.None).Take(5);
var log = ex.ToString() + NL + String.Join(NL, stack) + NL + "   ...";

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2018-07-19
    • 2013-07-29
    • 2020-04-21
    • 1970-01-01
    • 2017-08-06
    相关资源
    最近更新 更多