2012-04-12 7 views
11

In meinem Code stoße ich auf eine Situation, in der ein System.Reflection.TargetInvocationException geworfen wird. In einem bestimmten Fall weiß ich, wie ich die Root-Ausnahme behandeln möchte, aber ich möchte alle anderen Ausnahmen werfen. Ich kann mir zwei Möglichkeiten vorstellen, aber ich bin mir nicht sicher, was besser ist.Den Typ einer inneren Ausnahme prüfen

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

Ich bin mir bewusst, dass Ausnahmen im Allgemeinen wirft langsam, so dass ich das Gefühl, die erste Methode möglicherweise schneller sein würde. Oder gibt es einen besseren Weg, an den ich nicht gedacht habe?

+2

2 ist faszinierend, imho 1 besser lesbar und wahrscheinlich besser von einer Performance-Sicht ist. – Gabber

+0

Frage: Was ist der Anruf, der 'TargetInvocationException' verursacht? Ist es dein Code oder eine dritte Partei? –

+0

Es ist generierter Code, der aus der Datenbank liest. – geekchic

Antwort

17

Jede Ihrer vorgeschlagenen Lösungen hat ein eigenes Problem. Die erste Methode überprüft, dass der Typ der inneren Ausnahme genau der Typ ist, der erwartet wird. Das bedeutet, dass ein abgeleiteter Typ nicht übereinstimmt, was möglicherweise nicht Ihren Vorstellungen entspricht.

Die zweite Methode überschreibt den Stack-Trace der inneren Exception mit der aktuellen Stack-Position, wie Dan Puzey erwähnt. Das Zerstören des Stack-Trace kann den einen Lead zerstören, den Sie benötigen, um einen Bug zu beheben.

Die Lösung ist im Grunde, was Darkgray geschrieben, mit Nicks Vorschlag und mit einem zusätzlichen Vorschlag meiner eigenen (im 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. 
    } 
} 

Wenn Sie eine Ausnahme erneut zu werfen, die Sie stellt sich heraus, können 't Handle, nicht throw ex;, da dies die Stack-Trace überschreiben wird. Verwenden Sie stattdessen throw;, die den Stack-Trace erhält. Es bedeutet im Wesentlichen "Ich wollte diese catch Klausel nicht eingeben, so tun, als ob ich nie die Ausnahme gefangen".

Aktualisierung: C# 6.0 bietet eine viel bessere Syntax über Exception Filter:

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 für den Unterschied zwischen 'throw;' und 'throw ex;' – geekchic

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

oder

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

oder

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

Warum nicht das Schlüsselwort 'is' verwenden? – Nick

+0

Ihr Code unterscheidet sich nicht funktional vom ursprünglichen ersten Vorschlag, und Sie haben auch keine Begründung oder Begründung für den Code angegeben. –

1

Ihr # 2 ist auf jeden Fall eine interessante Lösung!

Sie wollen allerdings vorsichtig sein: wird haben TargetInvocationException typischerweise durch eine andere Komponente geworfen worden, als es zuerst InnerException gefangen. Wenn du throw ex.InnerException hast, wirst du einige Informationen zerstören (wie die Stack-Spur), weil du sie von einem anderen Ort wegwirfst.

Also von den zwei, die Sie vorgeschlagen haben, würde ich definitiv vorschlagen, mit # 1 zu gehen. Ich kenne keine Alternative innerhalb der Struktur, die Sie haben. Die InnerException wird jedoch ursprünglich an anderer Stelle geworfen - es lohnt sich zu untersuchen, ob es einen eleganteren Ort gibt, um diesen Fehler zu behandeln, näher an dem Ort, an dem die Ausnahme ausgelöst wird.

Verwandte Themen