我已确认在VS2005中出现了相同的行为,因此我错误地称它为.NET(1.1)的错误。
我将保留原始问题,但我的修改后的问题是:如何使Visual Studio在调用堆栈窗口中给出我捕获并重新抛出的异常的堆栈跟踪,而不仅仅显示从throw
语句点开始的调用堆栈?
情况是我在运行时决定全局异常处理程序是否开启--如果关闭,我希望VS捕获异常,以便我可以逐步查看调用堆栈以找出出错原因。
以前,全局异常处理程序要么编译进程序中,要么不编译。但情况已经改变,现在我们需要在运行时决定--看起来我可能需要回到使用宏的方式,但没有宏:
if (allow_bubble_up)
{
Foo();
}
else
{
try
{
Foo();
}
catch (Exception e)
{
GlobalExceptionHandler(e);
}
}
但是对于我来说,那种方法感觉极其不符合DRY原则。
显然,在.NET 1.1中有一个bug,即如果你使用空的
throw
语句重新抛出已捕获的异常,那么堆栈跟踪将从该throw
语句所在的位置开始,而不是重新抛出整个异常的堆栈跟踪--至少我在几个博客上看到它被称为一个bug,但我无法获得更多的信息。
更具体地说,在QuickWatch中,$exception
的StackTrace
属性显示了正确的数据,但是在VS的调用堆栈窗口中,只显示到throw语句的级别。
在此示例代码中,我只能看到Main
的一个深度为1级的堆栈跟踪,尽管我应该能够看到对Foo
的几次调用的堆栈跟踪。
static public void Foo(int i)
{
if (i > 4)
{
throw new ArgumentOutOfRangeException();
}
Foo(i + 1);
}
static void Main(string[] args)
{
bool allow_bubble_up = true;
try
{
Foo(0);
}
catch (Exception e)
{
if (allow_bubble_up)
{
// stack trace just shows Main
throw;
// also just shows Main
//throw new Exception("asdf", e);
// STILL just shows Main
//throw e;
}
else
{
System.Console.WriteLine(e);
}
}
}
Fabrice Marguerie's blog介绍了如何解决.NET 2.0+的某些类型的重新抛出堆栈跟踪问题,在底部他建议查看Chris Taylor的博客以了解如何在.NET 1.1中实现。我不得不搜索一下archive.org才找到它。我认为我已经正确实现了它,但我仍然只在主线程上收到一个堆栈跟踪--他的解释并不是非常清楚,而且我希望尽可能少地对代码库进行更改(在另一个方法中包装现有的功能集)。
我可以在捕获和重新抛出异常的属性中看到正确的堆栈跟踪,但VS显示的可导航堆栈跟踪是无用的,因为它仅从throw
语句跟踪。如果我从未捕获和重新抛出异常,我会得到完整和正确的堆栈跟踪。
如何在VS中显示正确的堆栈跟踪? 我希望有一种简单的解决方法,可能是我搜索了错误的术语。
不幸的是,这必须是VS2003 + C#。
如果不清楚,请参见以下截图(您可能需要右键单击并查看图像):
alt text http://img257.imageshack.us/img257/1124/40727627.png