2009-11-08 5 views

Antwort

127

Die Konstruktionen

try { ... } 
catch() { ... } /* You can even omit the() here */ 

try { ... } 
catch (Exception e) { ... } 

sind insofern ähnlich beide werden jede Ausnahme innerhalb des try Block geworfen fangen (und, es sei denn Sie einfach diese werden mit den Ausnahmen zu protokollieren, vermieden werden sollte). Jetzt auf diese aussieht:

try { ... } 
catch() 
{ 
    /* ... */ 
    throw; 
} 

try { ... } 
catch (Exception e) 
{ 
    /* ... */ 
    throw; 
} 

try { ... } 
catch (Exception e) 
{ 
    /* ... */ 
    throw e; 
} 

Die ersten und die zweiten Try-Catch-Blöcke sind genau die gleiche Sache, sie einfach die aktuelle Ausnahme erneut auslösen, und diese Ausnahme wird seine „Quelle“ halten und den Stack-Trace.

Der dritte try-catch-Block ist anders. Wenn es die Ausnahme auslöst, ändert es die Quelle und den Stack-Trace, so dass es scheint, dass die Ausnahme von dieser Methode aus genau dieser Zeile throw e für die Methode, die diesen try-catch-Block enthält, ausgelöst wurde.

Welche sollten Sie verwenden? Es hängt wirklich von jedem Fall ab.

Nehmen wir an, Sie haben eine Person Klasse mit einer .Save() Methode, die es in einer Datenbank beharrt. Angenommen, Ihre Anwendung führt die Methode Person.Save() irgendwo aus. Wenn Ihre Datenbank es ablehnt, die Person zu speichern, löst .Save() eine Ausnahme aus. Sollten Sie in diesem Fall throw oder throw e verwenden? Es hängt davon ab.

Was ich lieber tut:

try { 
    /* ... */ 
    person.Save(); 
} 
catch(DBException e) { 
    throw new InvalidPersonException(
     "The person has an invalid state and could not be saved!", 
     e); 
} 

Dies sollte die DbException als "Inner Exception" der neueren Ausnahme: throw setzen.Wenn Sie diese InvalidPersonException untersuchen, enthält der Stack-Trace also Informationen zurück zur Save-Methode (die möglicherweise ausreichen, um das Problem zu lösen), Sie haben jedoch weiterhin Zugriff auf die ursprüngliche Ausnahme, wenn Sie sie benötigen.

Als abschließende Bemerkung, wenn Sie eine Ausnahme erwarten, sollten Sie wirklich fangen, dass eine spezifische Ausnahme, und nicht eine allgemeine Exception, das heißt, wenn Sie einen InvalidPersonException erwarten sollten Sie bevorzugen:

try { ... } 
catch (InvalidPersonException e) { ... } 

zu

try { ... } 
catch (Exception e) { ... } 

Viel Glück!

30

Die erste behält die Stack-Kurve bei, während die zweite sie zurücksetzt. Dies bedeutet, dass der Stack-Trace der Exception immer von dieser Methode startet, wenn Sie den zweiten Ansatz verwenden, und Sie verlieren den ursprünglichen Exception-Trace, der für jemanden, der Exception-Protokolle liest, katastrophal sein könnte, da er nie den ursprünglichen Grund der Exception herausfinden wird .

Der zweite Ansatz könnte nützlich sein, wenn Sie zusätzliche Informationen zu dem Stack-Trace hinzugefügt werden sollen, aber es wird wie folgt verwendet:

try 
{ 
    // do something 
} 
catch (Exception ex) 
{ 
    throw new Exception("Additional information...", ex); 
} 

Es gibt einen Blog post die Unterschiede zu diskutieren.

+0

Nun, die große Sachen zu wissen ist! – Myles

+0

Warum also die Sekunde dann benutzen? ist es besser, nur die erste zu verwenden? – Karim

+1

Die zweite ist nützlich, wenn Sie nach bestimmten Ausnahmen suchen müssen - OutOfRangeException kommt in den Sinn - oder müssen Sie die Nachricht, etc. Die erste scheint eine Wildcard-Ausnahmebehandler ähnlich wie try {} catch (...) { } in C++. –

6

sollten Sie

try { } 
catch(Exception e) 
{ throw } 

verwenden, wenn Sie es etwas mit der Ausnahme, bevor sie wieder zu werfen tun wollen (zB Anmeldung). Der einsame Wurf bewahrt die Stapelspur.

+0

und was passiert, wenn ich den "throw" hier durch einen "throw e" ersetze? – Karim

+3

Wie Darin darauf hinwies, wird "throw e" die Stapelspur zurücksetzen. –

4

Der Unterschied zwischen einem parameterlosen Catch und einem catch(Exception e) ist, dass Sie einen Verweis auf die Ausnahme erhalten. Ab Framework-Version 2 werden nicht verwaltete Ausnahmen in eine verwaltete Ausnahme eingeschlossen, sodass die parameterlose Ausnahme für nichts mehr nützlich ist.

Der Unterschied zwischen throw; und throw e; ist, dass die erste verwendet wird, um Ausnahmen erneut auszulösen und die zweite, um eine neu erstellte Ausnahme zu werfen. Wenn Sie die zweite verwenden, um eine Ausnahme erneut auszulösen, behandelt sie diese wie eine neue Ausnahme und ersetzt alle Stapelinformationen von der Stelle, an der sie ursprünglich ausgelöst wurde.

Also, Sie sollten keine der Alternativen in der Frage verwenden. Sie sollten den parameterlosen Catch nicht verwenden, und Sie sollten throw; verwenden, um eine Ausnahme erneut auszulösen.

Außerdem sollten Sie in den meisten Fällen für alle Ausnahmen eine spezifischere Ausnahmeklasse als die Basisklasse verwenden. Sie sollten nur die Ausnahmen abfangen, die Sie erwarten.

try { 
    ... 
} catch (IOException e) { 
    ... 
    throw; 
} 

Wenn Sie Informationen hinzufügen möchten, wenn die Ausnahme Erneutes Auslösen Sie eine neue Ausnahme mit der ursprünglichen Ausnahme als innere Ausnahme erstellen Sie alle Informationen preservere:

try { 
    ... 
} catch (IOException e) { 
    ... 
    throw new ApplicationException("Some informative error message", e); 
} 
Verwandte Themen