2009-11-08 7 views

Respuesta

127

Las construcciones

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

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

son similares en que ambas se captura cada excepción lanzada dentro del bloque try (y, a menos que usted simplemente está usando este para registrar las excepciones, deben ser evitarse). Ahora miran siguientes:

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

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

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

El primer y segundo bloques try-catch son exactamente lo mismo, simplemente volver a lanzar la excepción actual, y que mantendrán su excepción "fuente" y el seguimiento de la pila.

El tercer bloque try-catch es diferente. Cuando lanza la excepción, cambiará el origen y el seguimiento de la pila, de modo que parezca que se ha lanzado la excepción desde este mismo método, desde esa misma línea throw e en el método que contiene ese bloque try-catch.

¿Cuál debería usar? Realmente depende de cada caso.

Digamos que tiene una clase Person con un método .Save() que lo mantendrá en una base de datos. Supongamos que su aplicación ejecuta el método Person.Save() en alguna parte. Si su DB se niega a guardar la Persona, entonces .Save() emitirá una excepción. ¿Debería usar throw o throw e en este caso? Bueno, eso depende.

lo que prefiero está haciendo:

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

Esto debería poner el DBException como la "excepción interna" de la excepción más reciente de ser un tiro.Por lo tanto, cuando inspeccione esta InvalidPersonException, el seguimiento de la pila contendrá información de regreso al método Save (que podría ser suficiente para que usted resuelva el problema), pero aún tendrá acceso a la excepción original si la necesita.

Como observación final, cuando se está esperando una excepción, que realmente debería ponerse que una excepción específica, y no un general Exception, es decir, si usted está esperando un InvalidPersonException se debe preferir:

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

a

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

Buena suerte!

30

El primero conserva el seguimiento de la pila mientras que el segundo lo restablece. Esto significa que si usa el segundo enfoque, el rastro de la excepción siempre comenzará desde este método y perderá el rastro de excepción original que podría ser desastroso para alguien que lea registros de excepciones ya que nunca descubrirá la causa original de la excepción .

El segundo enfoque podría ser útil cuando se desea añadir información adicional al seguimiento de la pila pero se usa de esta manera:

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

Hay un blog post discutir las diferencias.

+0

Bueno, eso es una gran cosa para saber! – Myles

+0

entonces ¿por qué usar el segundo entonces? ¿es mejor usar solo el primero? – Karim

+1

Lo segundo es útil cuando necesita verificar excepciones específicas, como OutOfRangeException, o tener que registrar el mensaje, etc. El primero parece ser un manejador de excepciones de comodines similar a try {} catch (...) { } en C++. –

6

Debe utilizar

try { } 
catch(Exception e) 
{ throw } 

si quieres hacer algo con la excepción antes de volver a tirarlo (registro, por ejemplo). El lanzamiento solitario conserva el seguimiento de pila.

+0

y ¿qué pasará si reemplazo el "tiro" aquí con un "tiro e"? – Karim

+3

Como señaló Darin, "arrojar e" restablecerá el seguimiento de la pila. –

4

La diferencia entre un catch sin parámetros y un catch(Exception e) es que obtiene una referencia a la excepción. Desde la versión de marco 2, las excepciones no administradas se envuelven en una excepción administrada, por lo que la excepción sin parámetros ya no es útil para nada.

La diferencia entre throw; y throw e; es que la primera se usa para replantear excepciones y la segunda se utiliza para lanzar una excepción recientemente creada. Si usa el segundo para volver a lanzar una excepción, lo tratará como una nueva excepción y reemplazará toda la información de la pila desde donde se lanzó originalmente.

Entonces, no debe usar ninguna de las alternativas en la pregunta. No debe usar la captura sin parámetros, y debe usar throw; para volver a lanzar una excepción.

Además, en la mayoría de los casos, debe usar una clase de excepción más específica que la clase base para todas las excepciones. Solo debería captar las excepciones que anticipa.

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

Si desea añadir cualquier información cuando Regeneración de la excepción, se crea una nueva excepción, con la excepción original como una excepción interna a preservere toda la información:

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