2012-04-12 63 views
11

在我的代码中,我遇到了引发System.Reflection.TargetInvocationException的情况。在一个特定的情况下,我知道我想如何处理根异常,但我想抛出所有其他异常。我可以考虑两种方法来做这件事,但我不确定哪种方法更好。检查内部异常的类型

1.

try 
{ 
    //code 
} 
catch (System.Reflection.TargetInvocationException ex) 
{ 
    if (typeof(ex.InnerException) == typeof(SpecificException)) 
    { 
     //fix 
    } 
    else 
    { 
     throw ex.Innerexception; 
    } 
} 

2.

try 
{ 
    //code 
} 
catch (System.Reflection.TargetInvocationException ex) 
{ 
    try 
    { 
     throw ex.InnerException; 
    } 
    catch (SpecificException exSpecific) 
    { 
     //fix 
    } 
} 

我知道,在一般抛出异常缓慢,所以我觉得第一种方法将可能更快。或者,有没有更好的方法来做到这一点,我没有想到?

+2

2是引人入胜,IMHO 1更可读的,可能从性能的角度来看较好。 – Gabber 2012-04-12 09:08:05

+0

问题:抛出'TargetInvocationException'的调用是什么?它是你的代码还是第三方? – 2012-04-12 09:16:15

+0

它是从db读取的生成代码。 – geekchic 2012-04-12 09:17:51

回答

17

您提出的每种解决方案都有其自己的问题。

第一种方法检查内部异常的类型是,确切地说是预期的类型。这意味着派生类型不匹配,这可能不是你想要的。

第二种方法用Dan Puzey提到的方法用当前堆栈位置覆盖内部异常的堆栈跟踪。销毁堆栈跟踪可能会破坏您需要的一条线索以修复错误。

的解决方案基本上是什么深灰发布,与尼克的建议,并与我自己的补充意见(在else):

try 
{ 
    // Do something 
} 
catch (TargetInvocationException ex) 
{ 
    if (ex.InnerException is SpecificException) 
    { 
     // Handle SpecificException 
    } 
    else if (ex.InnerException is SomeOtherSpecificException) 
    { 
     // Handle SomeOtherSpecificException 
    } 
    else 
    { 
     throw; // Always rethrow exceptions you don't know how to handle. 
    } 
} 

如果你想重新抛出原来可以例外不处理,不要throw ex;,因为它会覆盖堆栈跟踪。取而代之的是使用throw;来保存堆栈跟踪。它基本上意味着“我实际上不想进入这个catch条款,假装我从未发现异常”。

更新: C#6。0经由异常过滤器提供一个更好的语法:

try 
{ 
    // Do something 
} 
catch (TargetInvocationException ex) when (ex.InnerException is SpecificException) 
{ 
    // Handle SpecificException 
} 
catch (TargetInvocationException ex) when (ex.InnerException is SomeOtherSpecificException) 
{ 
    // Handle SomeOtherSpecificException 
} 
+0

+1用于指出'throw;'和'throw ex;之间的区别' – geekchic 2012-04-12 10:05:27

-2
try 
{ 
    //code 
} 
catch (System.Reflection.TargetInvocationException ex) 
{ 
    if (ex.InnerException is SpecificException) 
    { 
     //fix 
    } 
    else 
    { 
     throw ex.InnerException; 
    } 
} 

try 
{ 
    //code 
} 
catch (System.Reflection.TargetInvocationException ex) 
{ 
    SpecificException spExc = ex.InnerException as SpecificException; 
    if (spExc != null) 
    { 
     bla-bla spExc 
    } 
    else 
    { 
     throw ex.InnerException; 
    } 
} 

try 
{ 
    //code 
} 
catch (System.Reflection.TargetInvocationException ex) 
{ 
    if (ex.InnerException.GetType() == typeof(SpecificException)) 
    { 
     //fix 
    } 
    else 
    { 
     throw ex.InnerException; 
    } 
} 
+0

为什么不使用'is'关键字? – Nick 2012-04-12 09:11:27

+0

您的代码在功能上与原始的第一条建议没有区别,您也没有为代码提供任何推理或理由。 – 2012-04-12 09:15:08

1

你的#2绝对是一个有趣的解决方案!

你要小心,但:TargetInvocationException通常会被抛出由其他组件时,第一次InnerException。如果你throw ex.InnerException你会破坏它包含的一些信息(比如堆栈跟踪),因为你正在从不同的位置重新抛出它。

所以你提出的两个,我肯定会建议去#1。我不知道你有什么结构可供选择。然而,InnerException将会在其他地方被抛出 - 值得研究是否有更优雅的地方来处理这种失败,更接近抛出异常的地方。