在.NET异常中保留原始的StackTrace / LineNumbers [英] Preserving original StackTrace/LineNumbers in .NET Exceptions
问题描述
了解 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屋!