如何重新抛出TargetInvocationException的内部异常,而不会丢失堆栈跟踪 [英] How to rethrow the inner exception of a TargetInvocationException without losing the stack trace

查看:358
本文介绍了如何重新抛出TargetInvocationException的内部异常,而不会丢失堆栈跟踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有许多方法使用 Delegate.DynamicInvoke 调用。这些方法中的一些使数据库调用,我想有能力捕获一个 SqlException ,而不是捕获 TargetInvocationException 并且通过它的内部寻找发现实际出错了。

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;
 }

PreserveStackTrace 是一个扩展方法我修复了感谢另一篇文章(我不知道它实际上是什么)。但是,这并不会保留跟踪:

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;
}

这种技术由Rx使用(并被他们作为扩展方法公开 Exception.PrepareForRethrow ),也由Async CTP通过其自动展开系统(没有公开的API)使用。

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).

但是,请注意,这种技术在技术上不受支持。希望Microsoft将来会为此添加官方API。建议已被打开在Microsoft Connect上,如果你想投票。

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.

更新:已将官方API添加到.NET 4.5: a href =http://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo%28v=vs.110%29.aspx =noreferrer> ExceptionDispatchInfo

Update: An official API has been added to .NET 4.5: ExceptionDispatchInfo.

这篇关于如何重新抛出TargetInvocationException的内部异常,而不会丢失堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆