public static class LogAndThrow
{
public static void Message<TException>(string message) where TException : Exception
{
// Log message here
var constructor =
typeof(TException).GetConstructor(new[] { typeof(string) });
throw (TException)constructor.Invoke(new[] { message });
}
}
当然,这段代码有点粗糙(我为了这篇文章进行了删减),但它能够工作。
然而,作为一名通过反射构建异常的人,我对堆栈跟踪中包含“LogAndThrow.Message()”行感到不满。
因此,我开始着手解决这个问题 :-)
我使用了一些序列化和其他技巧来替换堆栈跟踪,这些方法都非常愚笨,也很暴力。但我想弄清楚这个问题。
但我注意到了一些奇怪的事情:
var exception = new Exception();
throw exception;
在异常创建之后,但在抛出异常之前,唯一设置的是消息(Message)。堆栈跟踪(Stack trace)等为空。
以上内容等同于以下IL代码:
.locals init (
[0] class [mscorlib]System.Exception exception)
nop
newobj instance void [mscorlib]System.Exception::.ctor()
stloc.0
ldloc.0
throw
在我看来,'throw' 的 IL 做了比仅仅将引用带到堆栈上更多的事情。
有人知道当 IL 遇到 'throw' 时,运行时会对堆栈上的异常做些什么吗?
我们下面使用的技巧与 throw 中的“魔法”有关:
这段代码很糟糕、错误。只是一个科学实验,不应该被投入生产
var e = new Exception("message here");
try
{
throw e;
}
finally
{
// Get the private file _stackTraceString with reflection
field.SetValue(e, new StackTrace(1).ToString());
}
catch
中通过throw e;
重新抛出异常的原因是不好的 - 它会修改对象中有关堆栈跟踪的属性。 - IS4