如何重新抛出一个TargetInvocationException的内部异常不失堆栈跟踪 [英] How to rethrow the inner exception of a TargetInvocationException without losing the stack trace
问题描述
我有一个使用 Delegate.DynamicInvoke
调用许多方法。有些方法使数据库调用,我想必须抓住能力的SQLException
,而不是赶 TargetInvocationException
猎通过其胆找到什么真正出了问题。
我是用这个方法重新抛出,但它清除堆栈跟踪:
尝试
{
返回myDelegate.DynamicInvoke(参数);
}
赶上(TargetInvocationException前)
{
FUNC< TargetInvocationException,异常> getInner = NULL;
getInner =
委托(TargetInvocationException E)
{
如果(e.InnerException是TargetInvocationException)
返回getInner((TargetInvocationException)e.InnerException); 返回e.InnerException;
}; 例外内= getInner(除息);
。内preserveStackTrace();
扔内;
}
的 preserveStackTrace
方法是一个扩展方法我搞掂感谢另一篇文章(我不知道它实际上做)。然而,这不会出现preserve跟踪之一:
公共静态无效preserveStackTrace(这个例外五)
{
VAR CTX =新的StreamingContext(StreamingContextStates.CrossAppDomain);
VAR经理=新的ObjectManager(NULL,CTX);
变种SI =新的SerializationInfo(e.GetType(),新FormatterConverter()); e.GetObjectData(SI,CTX);
mgr.RegisterObject(E,1,SI);
mgr.DoFixups();
}
如果你只是想重新引发内部异常preserving它的堆栈跟踪,你可以用这样的方法做到这一点:
公共静态无效的重新抛出(此异常前)
{
typeof运算(例外).GetMethod(prepForRemoting
BindingFlags.NonPublic可| BindingFlags.Instance)
.Invoke(例如,新的对象[0]);
扔恩;
}
此技术被用来以Rx(并且由他们暴露为扩展方法异常。prepareForRethrow
),并还用于通过异步CTP通过其自动-unwrapping系统(没有公开暴露的API)。
请注意,但是,这种技术在技术上是不支持的。希望微软将在未来增加一个官方的API这一点。有人建议<一href=\"https://connect.microsoft.com/VisualStudio/feedback/details/633822/allow-$p$pserving-stack-traces-when-rethrowing-exceptions\">has被打开微软连接,如果你想为它投票。
更新:一个官方的API已经被添加到.NET 4.5:<一href=\"http://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo%28v=vs.110%29.aspx\"><$c$c>ExceptionDispatchInfo$c$c>.
I have many methods which are calling using Delegate.DynamicInvoke
. Some of these methods make database calls and I would like to have the ability to catch a SqlException
and not catch the TargetInvocationException
and hunt through its inners to find what's actually gone wrong.
I was using this method to rethrow but it clears the stack trace:
try
{
return myDelegate.DynamicInvoke(args);
}
catch(TargetInvocationException ex)
{
Func<TargetInvocationException, Exception> getInner = null;
getInner =
delegate(TargetInvocationException e)
{
if (e.InnerException is TargetInvocationException)
return getInner((TargetInvocationException) e.InnerException);
return e.InnerException;
};
Exception inner = getInner(ex);
inner.PreserveStackTrace();
throw inner;
}
The PreserveStackTrace
method is an extension method I fixed up thanks to another post (I don't know what it actually does). However, this doesn't appear to preserve the trace either:
public static void PreserveStackTrace(this Exception e)
{
var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
var mgr = new ObjectManager(null, ctx);
var si = new SerializationInfo(e.GetType(), new FormatterConverter());
e.GetObjectData(si, ctx);
mgr.RegisterObject(e, 1, si);
mgr.DoFixups();
}
If you just want to re-throw an inner exception preserving its stack trace, you can do it with a method like this:
public static void Rethrow(this Exception ex)
{
typeof(Exception).GetMethod("PrepForRemoting",
BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(ex, new object[0]);
throw ex;
}
This technique is used by Rx (and is exposed by them as an extension method Exception.PrepareForRethrow
) and is also used by the Async CTP by its automatic-unwrapping system (without a publicly-exposed API).
Note, however, that this technique is technically unsupported. Hopefully Microsoft will add an official API for this in the future. A suggestion has been opened on Microsoft Connect if you would like to vote for it.
Update: An official API has been added to .NET 4.5: ExceptionDispatchInfo
.
这篇关于如何重新抛出一个TargetInvocationException的内部异常不失堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!