我有一个不寻常的情况,我有一个非常简单的异常被抛出并在同一方法中捕获。它不会被重新抛出(天真的程序员通常会遇到这样的问题)。然而它的 StackFrame 只包含一个当前方法。它看起来是这样的:
at (my class).MyMethod() in C:\(my file path and line)
实际上,VS2010 调试器的调用堆栈中可能有 30 个方法导致此情况,涉及六个不同的程序集。所有这些似乎不可能被优化掉。此外,这段代码是内置的调试模式,无优化,对于.NET 4。我什至有(基于http://msdn.microsoft.com/en-us/library/9dd8z24x.aspx http://msdn.microsoft.com/en-us/library/9dd8z24x.aspx) .ini 文件(包括名为 [app].vshost.ini 的文件)位于同一文件夹中,其中包含:
[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0
此外,方法调用不在方法的末尾,因此尾递归优化似乎更不可能。
至于它是如何调用的:调用堆栈上没有使用反射,没有任何类型的 Invoke() 或 BeginInvoke()。这只是通过单击按钮产生的一长串调用。单击处理程序位于调用堆栈中大约 10 个调用处。在其下面有常见的 WndProc、NativeWindow.Callback、本机/托管转换和消息循环。这最终是在从 C# EXE 程序集运行的 ShowDialog() 调用中进行的。
现在,我发现我可以在 catch 处理程序中构造 StackTrace 类的实例,并且如果我传递 Exception 对象,调用堆栈也会很短。相反,如果我只调用不带参数的 new StackTrace(),它会生成完整的调用堆栈。
我尝试使用 Reflector 来调试抛出的 Exception 类的内部结构及其构造的调用堆栈,但我无法在 Exception 或 StackTrace 中设置断点。我可以在 Environment.GetStackTrace() 中设置它们,并且这个方法(Exception 调用的)在构造和抛出过程中似乎不会被调用,但我不知道调试器是否真的正常工作。 (这个方法确实会被其他一些事情触发,所以我不知道该怎么做。)
以下是该方法的摘录:
private void MyMethod()
{
...
try
{
throw new ApplicationException("Test failure");
}
catch (Exception e)
{
StackTrace stackTrace1 = new StackTrace(e);
StackTrace stackTrace2 = new StackTrace(e, false);
StackTrace stackTrace3 = new StackTrace(e, true);
StackTrace stackTrace4 = new StackTrace();
string STs = stackTrace1.ToString() + "\n---\n"
+ stackTrace2.ToString() + "\n---\n"
+ stackTrace3.ToString() + "\n---\n"
+ stackTrace4.ToString();
Log(EventSeverity.Debug, STs);
...
}
}
这真的非常简单:抛出异常,捕获并记录它。
无论是在调试器中还是在独立运行(单行调用堆栈)时,我都会得到相同的结果。我知道我在我们的代码库的其他地方看到过这个问题。以前我认为这是由于重新抛出异常,但在很多情况下,我们直接在初始 catch 块内记录。我很困惑,我所做的所有网络搜索都没有产生任何结果。
作为对所提供答案的评论添加有点太多了,但这里有更多信息:
我现在看到这种行为正在讨论http://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/ http://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/它实际上是在http://msdn.microsoft.com/en-us/library/system.exception.stacktrace.aspx http://msdn.microsoft.com/en-us/library/system.exception.stacktrace.aspx(尽管我认为人们很容易错过他们在那里所说的内容)。
所以我想我的“解决方案”会有点碰运气。我们有一个通常调用来格式化异常的中心方法。在该方法中,我将创建一个带有或不带有 Exception 对象的新 StackTrace()。然后,我将查找异常堆栈跟踪底部的方法,并在 new StackTrace() 中显示该方法下方的所有内容,表明该方法是由该系列调用调用的。
当然,缺点是如果不使用此方法,则信息将不存在。但我不得不期待某些地方会发生某种代码更改。