Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在不丢失堆栈跟踪的情况下重新显示TargetInvocationException的内部异常_C#_Exception Handling_Stack Trace_Targetinvocationexception_Inner Exception - Fatal编程技术网

C# 如何在不丢失堆栈跟踪的情况下重新显示TargetInvocationException的内部异常

C# 如何在不丢失堆栈跟踪的情况下重新显示TargetInvocationException的内部异常,c#,exception-handling,stack-trace,targetinvocationexception,inner-exception,C#,Exception Handling,Stack Trace,Targetinvocationexception,Inner Exception,我有许多方法正在使用Delegate.DynamicInvoke调用。其中一些方法会进行数据库调用,我希望能够捕获SqlException,而不是捕获targetingException,并搜索其内部以查找实际出了什么问题 我正在使用此方法重新刷新,但它会清除堆栈跟踪: try { return myDelegate.DynamicInvoke(args); } catch(TargetInvocationException ex) { Func<Targe

我有许多方法正在使用
Delegate.DynamicInvoke
调用。其中一些方法会进行数据库调用,我希望能够捕获
SqlException
,而不是捕获
targetingException
,并搜索其内部以查找实际出了什么问题

我正在使用此方法重新刷新,但它会清除堆栈跟踪:

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

IIRC不可能完全保留异常,但是可以通过一些反射来保留堆栈跟踪。下面是一篇博客文章,描述了如何做到这一点:

您需要记住,为什么.NET会用TargetInvocationException包装异常,而不仅仅是让原始异常通过。这有一个很好的理由,不清楚异常的真正原因来自哪里。是因为DynamicInvoke()调用被阻塞了吗?并非不可能,编译器无法确保传递正确的参数。还是被调用的目标方法本身抛出了所有错误


您需要了解这两者,才能判断异常的真正原因。如果确实是DynamicInvoke()调用的问题,那么故意隐藏TargetInvocationException将使您很难诊断问题的根源。避免这样做。

如果您只想重新抛出一个保留堆栈跟踪的内部异常,可以使用如下方法:

public static void Rethrow(this Exception ex)
{
  typeof(Exception).GetMethod("PrepForRemoting",
      BindingFlags.NonPublic | BindingFlags.Instance)
      .Invoke(ex, new object[0]);
  throw ex;
}
Rx使用该技术(并将其作为扩展方法
Exception.prepareforethrow
)公开),异步CTP也通过其自动展开系统使用该技术(无公开的API)

但是,请注意,这种技术在技术上是不受支持的。希望微软将来能为此添加一个官方API。如果您想投票支持Microsoft Connect,请提供有关它的建议


更新:一个官方API已添加到.NET 4.5:。

我理解这一推理,但由于显式捕获特定错误的灵活性已不复存在,因此编写消费代码变得更加困难。无论如何,在这种情况下捕获异常非常困难。您对委托目标一无所知,无法猜测它是如何改变程序状态的。因此,在处理异常时无法恢复状态。TIE混淆问题的一种情况是,如果您同时控制引发异常的“内部”代码和要处理异常的外部代码。如果使用将内部代码封装在动态代理中的东西来注入内部代码,那么现在就更难捕获您从内部代码抛出的异常。例如,在ORM中,某些实体类可能会被包装,这最好是周围的代码不需要关心。需要注意的一点是:4.5中的ExceptionDispatchInfo意味着,当Rx根据您的目标是4.0还是4.5重新触发异常时,您会看到不同于Rx的调用堆栈。当目标为4.5而不是4.0时,未处理的ONERROR将使用原始堆栈跟踪重新恢复。更好的解决方案是查看,而不是使用?无论如何,如果没有可用的话,最好使用
PrepForRemoting
ExceptionDispatchInfo。@Kiquenet:当我写这个答案时,
ExceptionDispatchInfo
还不存在。当它出来时,我更新了这个答案,提到现在有一个正式的解决方案。找不到可能的副本
public static void Rethrow(this Exception ex)
{
  typeof(Exception).GetMethod("PrepForRemoting",
      BindingFlags.NonPublic | BindingFlags.Instance)
      .Invoke(ex, new object[0]);
  throw ex;
}