在.NET异常中保留原始的StackTrace / LineNumbers [英] Preserving original StackTrace/LineNumbers in .NET Exceptions

查看:176
本文介绍了在.NET异常中保留原始的StackTrace / LineNumbers的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

了解 throw ex throw 之间的区别,为什么在此示例中保留原始的StackTrace:

Understanding the difference between throw ex and throw, why is the original StackTrace preserved in this example:

    static void Main(string[] args)
    {
        try
        {
            LongFaultyMethod();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
        }
    }

    static void LongFaultyMethod()
    {
        try
        {
            int x = 20;
            SomethingThatThrowsException(x);
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void SomethingThatThrowsException(int x)
    {
        int y = x / (x - x);
    }

但不在这一个:

    static void Main(string[] args)
    {
        try
        {
            LongFaultyMethod();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
        }
    }

    static void LongFaultyMethod()
    {
        try
        {
            int x = 20;
            int y = x / (x - 20);
        }
        catch (Exception)
        {
            throw;
        }
    }

第二种情况是产生与会吗?

The second scenario is producing the same output as throw ex would?

在这两种情况下,都希望看到y被初始化的行号。

In both cases, one expects to see the line number where y is initialized.

推荐答案

我不知道这个限制是否在C#语言,CLI或Microsoft的这些实现之内,但是第二个例子是显式调用 Exception的情况。 InternalPreserveStackTrace 是必需的,如下列文章所示。由于这种方法是 internal ,它通常必须通过反射来调用。通过为该呼叫创建一个 Action< Exception> 可以几乎完全减轻涉及的性能问题,如此答案结尾所示。

I'm not sure whether this limitation is within the C# language, the CLI, or the Microsoft implementation of these, but your second example is a case where an explicit call to Exception.InternalPreserveStackTrace is required as documented in the following post. Since this method is internal, it generally has to be called through reflection. The performance issues involved in this can be almost completely alleviated by creating an Action<Exception> for the call, as shown at the end of this answer.

参考:重新发现异常并保留完整的调用堆栈跟踪

编辑:之后重新审视ECMA-335分区I§12.4.2(异常处理)和分区III§4.24(重新抛出),我现在相信您所看到的行为是CLR(Microsoft的CLI实现)中的语义错误。对行为的唯一具体引用是A rethrow 不会更改对象中的堆栈跟踪。在这里描述的情况下,重启事实上改变了堆栈跟踪,使得 PreserveStackTrace 为知道的CLR缺陷打了一个解决方法。

After reexamining ECMA-335 Partition I §12.4.2 (Exception handling) and Partition III §4.24 (rethrow), I now believe that the behavior you are seeing is a semantic error in the CLR (Microsoft's implementation of the CLI). The only specific reference to the behavior is "A rethrow does not change the stack trace in the object." In the case described here, the rethrow is in fact altering the stack trace, making the PreserveStackTrace hack a workaround for a know CLR flaw.

static void LongFaultyMethod() 
{ 
    try 
    { 
        int x = 20; 
        int y = x / (x - 20); 
    } 
    catch (Exception ex) 
    { 
        PreserveStackTrace(ex); // <-- add this line
        throw; 
    } 
} 

PreserveStackTrace 这里是从该博客条目中优化的一个:

PreserveStackTrace here is an optimization of the one from that blog entry:

private static readonly Action<Exception> _internalPreserveStackTrace =
    (Action<Exception>)Delegate.CreateDelegate(
        typeof(Action<Exception>),
        typeof(Exception).GetMethod(
            "InternalPreserveStackTrace",
            BindingFlags.Instance | BindingFlags.NonPublic));

public static void PreserveStackTrace(Exception e)
{
    _internalPreserveStackTrace(e);
}

这篇关于在.NET异常中保留原始的StackTrace / LineNumbers的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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