La diferencia entre try / catch / throw y try / catch (e) / throw e

Cuál es la diferencia entre

try { } catch { throw; } 

y

 try { } catch(Exception e) { throw e;} 

?

¿Y cuándo debería usar uno u otro?

Las construcciones

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

son similares en que ambos captarán todas las excepciones arrojadas dentro del bloque try (y, a menos que simplemente esté usando esto para registrar las excepciones, deben evitarse ). Ahora mira esto:

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

El primer y el segundo bloque try-catch son EXACTAMENTE la misma cosa, simplemente vuelven a lanzar la excepción actual, y esa excepción mantendrá su “origen” y el seguimiento de la stack.

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

¿Cual deberías usar? Realmente depende de cada caso.

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

Lo que prefiero es hacer:

 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 a DBException como la “Excepción interna” de la excepción más reciente que es throw. Por lo tanto, cuando inspeccione esta InvalidPersonException, el seguimiento de la stack 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 espere una excepción, realmente debería atrapar esa excepción específica, y no una Exception general, es decir, si espera una InvalidPersonException, debería preferir:

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

a

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

¡Buena suerte!

El primero conserva el seguimiento de la stack 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 desee agregar información adicional al seguimiento de la stack, pero se usa así:

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

Hay una publicación en el blog que discute las diferencias.

Deberías usar

 try { } catch(Exception e) { throw } 

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

La diferencia entre una captura sin parámetros y una 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 el primero se usa para replantear excepciones y el segundo se usa para lanzar una excepción recién 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 stack desde donde se lanzó originalmente.

Entonces, no debes usar ninguna de las alternativas en la pregunta. No deberías usar el catch sin parámetros, y deberías 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 agregar cualquier información al volver a lanzar la excepción, cree una nueva excepción con la excepción original como excepción interna para preservar toda la información:

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