Sam*_*Sam 15 .net exception line-numbers
理解throw ex和throw之间的区别,为什么在这个例子中保留了原始的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);
}
Run Code Online (Sandbox Code Playgroud)
但不是在这一个:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
第二种情况是产生与throw ex相同的输出?
在这两种情况下,人们都希望看到y被初始化的行号.
Sam*_*ell 17
我不确定这种限制是在C#语言,CLI还是Microsoft的实现中,但是您的第二个示例Exception.InternalPreserveStackTrace是需要显式调用的情况,如以下帖子中所述.由于这种方法internal,通常必须通过反射来调用.通过创建一个Action<Exception>for call,几乎可以完全缓解这方面涉及的性能问题,如本答案末尾所示.
编辑:在重新检查ECMA-335分区I§12.4.2(异常处理)和分区III§4.24(重新抛出)之后,我现在相信您看到的行为是CLR中的语义错误(Microsoft的CLI实现).对该行为的唯一具体引用是"A rethrow不会更改对象中的堆栈跟踪".在这里描述的情况下,重新抛出事实上正在改变堆栈跟踪,使得PreserveStackTracehack成为已知CLR缺陷的解决方法.
static void LongFaultyMethod()
{
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception ex)
{
PreserveStackTrace(ex); // <-- add this line
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
PreserveStackTrace 这是来自该博客条目的优化:
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);
}
Run Code Online (Sandbox Code Playgroud)