2012-04-12 92 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將會在其他地方被拋出 - 值得研究是否有更優雅的地方來處理這種失敗,更接近拋出異常的地方。