2012-04-12 11 views
11

私のコードでは、System.Reflection.TargetInvocationExceptionがスローされる状況を迎えています。 1つの特定のケースでは、私はルート例外をどのように処理したいのか知っていますが、他のすべての例外をスローしたいと思います。私はこれを行う2つの方法を考えることができますが、どちらが良いかわかりません。内部例外のタイプを確認する

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 1は、より読みやすく、おそらくパフォーマンスの観点から優れているIMHO、魅力的です。 – Gabber

+0

質問: 'TargetInvocationException'を投げている呼び出しは何ですか?それはあなたのコードですか、あるいは第三者ですか? –

+0

これはdbから読み取ったコードです。 – geekchic

答えて

17

提案されたソリューションには、それぞれ独自の問題があります。

最初のメソッドは、内部例外のタイプがで、正確にであることを確認します。つまり、派生した型は一致しません。これは、意図した型とは異なる可能性があります。

2番目の方法は、内部例外のスタックトレースを現在のスタック位置で上書きします(Dan Puzey氏の説明を参照)。スタックトレースを破棄すると、バグを修正するために必要なリードを破壊する可能性があります。あなたができる判明した例外を再スローする場合

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

ソリューションはDarkGrayはニックの提案をし、(elseで)自分の追加提案し、掲載するものは基本的ですそれはスタックトレースを上書きするので、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

-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

+0

あなたのコードは元の最初の提案と機能的に同じではないし、コードの推論も正当化もしていない。 –

1

あなたの#2は間違いなく興味深いソリューションです!

あなたはしかし、慎重になりたいん:それは最初のInnerExceptionをキャッチするときTargetInvocationExceptionは通常、別のコンポーネントによってスローされています。 throw ex.InnerExceptionの場合、別の場所から再投げているので、スタックトレースのような情報が破壊されます。

あなたが提案した2人のうち、私は間違いなく#1で行くことをお勧めします。私はあなたが持っている構造内の代替案を知らない。しかし、InnerExceptionはもともとどこかでスローされています。例外がスローされる場所に近い、このエラーを処理するためのよりエレガントな場所があるかどうかを調べる価値があります。