在.NET异常中保留原始堆栈跟踪/行号
理解throw ex和throw之间的区别,为什么在本例中保留原始堆栈跟踪:在.NET异常中保留原始堆栈跟踪/行号,.net,exception,line-numbers,.net,Exception,Line Numbers,理解throw ex和throw之间的区别,为什么在本例中保留原始堆栈跟踪: static void Main(string[] args) { try { LongFaultyMethod(); } catch (System.Exception ex) { Console.WriteLine(ex.StackTrace); }
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;
}
}
第二种情况是产生与throw ex相同的输出
在这两种情况下,人们都希望看到初始化y的行号。因为在第二个示例中,您正在从同一个方法重新引用异常。首先,它是从不同的方法抛出的,这就是原因。在一个方法作用域中,堆栈跟踪只能是一个 按照以下步骤操作,最好的方法是始终将异常包装在新异常中,以便查看异常深度 “如果在 相同的方法(异常堆栈跟踪) 只有一个行号信息 对于每个方法,您永远看不到堆栈跟踪 在方法A中,第2行 异常被抛出,然后在同一个 方法A,从生产线回收 17号,它只包含最后一个 异常所在的行号 “收回” 我很惊讶这么多的评论没有读到我的评论!!我在评论中写道,你应该安全地记录这篇评论,原因有很多,如果顶级代码吃掉了异常,而你不知道抛出了哪个异常,在哪里抛出了异常,那么记录可以帮助你将异常相交
如果您不需要登录,那么就不要捕获异常。我不确定这一限制是否在C语言、CLI或这些工具的Microsoft实现中,但您的第二个示例是需要显式调用
exception.InternalPreserveStackTrace
,如下文所述is方法是内部的
,通常必须通过反射来调用它。通过为调用创建操作
,可以几乎完全缓解其中涉及的性能问题,如本答案末尾所示
参考:
编辑:在重新检查ECMA-335分区I§12.4.2(异常处理)和分区III§4.24(重新刷新)后,我现在认为您看到的行为是CLR(Microsoft的CLI实现)中的语义错误。对该行为的唯一具体引用是“Arethrow
不会更改对象中的堆栈跟踪。”在这里描述的情况下,rethrow实际上是在更改堆栈跟踪,使PreserveStackTrace
成为已知CLR缺陷的一种解决方法
static void LongFaultyMethod()
{
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception ex)
{
PreserveStackTrace(ex); // <-- add this line
throw;
}
}
我知道这是一个可行的解决办法,但我仍然不明白为什么第二个示例中的重新引用不应该有正确的行号。@Akash Kava:你有参考资料吗?我不相信你完全理解OP的问题。@awe:我强烈反对。如果你没有任何有用的信息可以添加到外部异常中,然后您应该重新抛出异常,而不是将其包装。重新抛出将根本不保留行号,重新抛出将向您显示第一个堆栈项的行将是“重新抛出”的行",如果您的异常被捕获并在同一个函数中重新捕获,您将永远不知道异常被抛出的位置,让我们举一个明确的例子,XAML使用它,ASP.NET使用它,我认为Microsoft人员使用内部异常时不会不担心性能。@280Z:也不会。如果您没有有用的信息可添加,那么就根本不捕获异常.
static void LongFaultyMethod()
{
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception ex)
{
PreserveStackTrace(ex); // <-- add this line
throw;
}
}
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);
}