显示异常堆栈跟踪的重新抛出,而不是从抛出点的堆栈跟踪 [英] Showing stack trace of exception that is re-thrown, rather than stack trace from throw point

查看:509
本文介绍了显示异常堆栈跟踪的重新抛出,而不是从抛出点的堆栈跟踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经证实了在VS2005同样的行为,所以我错了称呼它一个.NET(1.1)的bug。



我要离开了原来的问题下面,但我的修订问题是:如何获取Visual Studio的给我,我在调用堆栈窗口捕获并重新抛出的异常的堆栈跟踪,而不是仅仅显示从罚球语句点调用栈?



的情况是,我决定的在运行时全球的异常处理程序是否开启或关闭 - 如果它的时候,我想VS捕获异常,所以我可以通过调用堆栈步骤搞清楚什么地方出了错



此前,全球异常处理要么编译成程序或没有。但是现在的情况已经改变,现在我们需要在运行时决定 - 它看起来像我可能需要回去做宏观的方式,但没有宏:

 如果(allow_bubble_up)
{
美孚();
}
,否则
{

{
美孚();
}
赶上(例外五)
{
GlobalExceptionHandler(E);
}
}



但这种方法感觉极其防干,给我。






显然没有在.NET 1.1中的错误在这里,如果你有一个空的罚球语句来重新抛出捕获的异常,堆栈跟踪是从哪儿了扔发生,而不是整个异常的堆栈跟踪被重新抛出 - 至少,我已经看到了叫上几个博客中的错误,但我一直没能得到它更多的信息<。 / p>

要成为一个更具体一点, $异常堆栈跟踪属性在快速监视显示正确的数据,但是在VS调用堆栈窗口只显示调用堆栈的throw语句的水平。



在此示例代码,我只能看到的1级深的堆栈跟踪,即使我的的看到一对夫妇的堆栈跟踪调用

 静态公共无效美孚(int i)以
{
如果(I> 4)
{
抛出新ArgumentOutOfRangeException();
}
美孚第(i + 1);
}

静态无效的主要(字串[] args)
{
布尔allow_bubble_up = TRUE;

{
美孚(0);
}
赶上(例外五)
{
如果(allow_bubble_up)
{
//堆栈跟踪只是显示主要
扔;

//也只是显示主要
//抛出新的异常(ASDF,E);

//仍然只是显示主要
//扔Ë;
}
,否则
{
的System.Console.WriteLine(E);
}
}
}

法布里斯Marguerie的博客显示了如何解决某种重新抛出堆栈跟踪.NET 2.0+,并在底部,他说要检查克里斯·泰勒对如何做到这一点在.NET 1.1博客。我不得不有点搜到的找到它archive.org 。我的认为的我正确地实现它,但是我仍然有一个堆栈跟踪就在主 - 他的解释并不十分清楚,我不希望惹的代码库(包装现有的设置在另一种方法的功能)的任何不必要的东西。



我可以看到在捕获并重新引发异常的性质正确的堆栈跟踪,但通航堆栈跟踪该VS显示是无用的,因为它只能从罚球语句跟踪。如果我从来没有赶上并重新抛出异常,我的的得到一个完整的和适当的堆栈跟踪。



如何获得在VS显示正确的堆栈跟踪?
我希望有一些简单的解决方法,那我刚刚一直在寻找错误的条款。



不幸的是,它必须是VS2003 + C#这一点。



如果它不是,否则清楚,这里有一个屏幕截图(你可能需要右键点击和查看图像):




解决方案

事实证明,如果你知道正确的字词进行搜索,有回答我试图解决这个问题。在MSIL,这就是所谓的例外过滤的和的它的的VS2003中提供



在Visual Basic.NET中,有一个叫结构追赶时, 当一个给定的谓词传递将只执行一个陷阱。 这个MSDN博客有一个很好的例子,如何追赶时,在VB.NET与结果(像我)的C#追赶掷。作品



最后,MSDN有工具,称为异常过滤器注入可以用来提供的语言(如C#异常过滤器的支持)不具有异常过滤器的支持。 - 美中不足的是,它运行在现有的装配,它确实是这样介绍的,如果你最终使用它的构建过程中一个尴尬的阶段。






在我发现异常过滤器注入,我最终实现了了一个功能代表和抓代表一个简短的功能,而只是调用功能是否异常被允许泡涨,否则称为一个try-catch功能,要求对捕获的异常渔获委托。



我的希望的做的,以某种方式使我发现异常过滤,是能够设置异常的类型赶在运行 - 如果异常被认为冒泡,我会试图捉住子类异常,将永远不会被调用,否则我会刚刚抓到一个基本的异常。我真的不知道这会在.NET 1.1或没有可能,因为这基本上就需要一个通用的 - 但它可能是可能与反思,我从来没有那么远在我的研究


I've confirmed this same behavior in VS2005, so I was wrong to call it a .NET (1.1) bug.

I'm leaving the original question below, but my revised question is this: how do I get Visual Studio to give me the stack trace of the exception I've caught and re-thrown in the Call Stack window, rather than only displaying the call stack from the point of the throw statement?

The situation is that I am deciding at runtime whether the global exception handler is on or off -- if it's off, I want VS to catch the exception so I can step through the call stack to figure out what went wrong.

Previously, the global exception handler was either compiled into the program or not. But the situation has changed, and now we need to decide at runtime -- it's looking like I might need to go back to the macro way of doing it, but without macros:

if (allow_bubble_up)
{
    Foo();
}
else
{
    try
    {
        Foo();
    }
    catch (Exception e)
    {
       GlobalExceptionHandler(e);
    }
}

But that approach feels extremely against DRY, to me.


Apparently there is a bug in .NET 1.1 where if you have an empty throw statement to re-throw a caught exception, the stack trace is started from where that throw occurred, instead of the stack trace of the whole exception being re-thrown -- at least, I've seen it called a bug on a couple blogs, but I haven't been able to get much more information on it.

To be a little more specific, the StackTrace property of $exception in QuickWatch shows the correct data, but the Call Stack window in VS only shows the call stack to the level of the throw statement.

In this sample code, I can only see a 1-level-deep stack trace of Main, even though I should see a stack trace of a couple calls to 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 shows how to work around re-thrown stack traces of some sort for .NET 2.0+, and at the bottom he says to check Chris Taylor's blog for how to do it in .NET 1.1. I had to search a bit to find it on archive.org. I think I implemented it correctly, but I still got a stack trace just at main -- his explanation wasn't terribly clear, and I'd prefer not to mess with the code base (wrap existing set of functionality in another method) any more than necessary.

I can see the correct stack trace in the properties of the caught and re-raised exception, but the navigable stack trace that VS shows is useless since it only tracks from the throw statement. If I never catch and re-throw the exception, I do get a full and proper stack trace.

How do I get the right stack trace displayed in VS? I'm hoping there's some sort of simple workaround, and that I've just been searching the wrong terms.

And unfortunately, it has to be VS2003+C# for this.

If it wasn't otherwise clear, here's a screenshot (you'll probably need to right-click and view image):

解决方案

It turns out that if you know the right terms to search, there is an answer to the problem I was trying to solve. In MSIL, it's called exception filtering, and it is available in VS2003.

In Visual Basic.NET, there is a construct called "catch-when" that will only execute a catch when a given predicate passes. This MSDN blog has a great example of how catch-when works in VB.NET vs. the results (like mine) of C#'s catch-throw.

Finally, MSDN has a tool called Exception Filter Inject that can be used to "provide exception filter support for languages (such as C#) which do not have exception filter support" - the catch is that it runs on an existing assembly, so it does introduce an awkward stage in the build process if you end up using it.


Before I found Exception Filter Inject, I ended up implementing a short function that took a "functional" delegate and a "catch" delegate, and would just call the functional if exceptions were allowed to bubble up, otherwise called the functional in a try-catch, calling the catch delegate on a caught exception.

What I wanted to do, that somehow lead me to find exception filtering, was to be able to set the type of the exception to catch at runtime - if exceptions were supposed to bubble up, I would have tried catching a subclassed Exception that would never be invoked, otherwise I would have just caught a basic Exception. I'm really not sure if that would have been possible in .NET 1.1 or not, since that basically would require a generic -- but it may have been possible with Reflection, I just never got that far in my research.

这篇关于显示异常堆栈跟踪的重新抛出,而不是从抛出点的堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆