throw vs throw ex ¿Cuál crees que no debes usar?

Si alguna vez te has puesto a pensar ¿Qué debo usar un throw o throw ex? y no sabias que elegir entonces te recomiendo que leas este post.
public void Tarea()
{
    try
    {
        //Ocurre una excepción
    }
    catch (Exception ex)
    {
        //Envio Mail
        //Log de errores
        //Etc
        //¿throw o throw ex;? 
    } 
 } 

Como vimos en el post anterior antes de usar un throw dentro de un Try-Catch se debe analizar el escenario para tomar esta decisión. Si estamos seguros de usarlo ahora puede surgir la siguiente pregunta:

Ahora ¿Qué debo usar: throw o throw ex?

Respuesta: Debes usar throw

A primera vista parecen lo mismo, pero con cada uno se obtienen resultados distintos. El principal afectado sera el equipo de desarrollo, cuando ocurran errores en producción y quieran saber ¿Donde? y ¿Por qué? ocurrió la excepción, debido a que se pierde el StackTrace orignal. El StackTrace sirve para saber en qué parte del código ocurrió la excepción y cuál fue la pila de llamadas realizadas hasta que ocurra. Al usar throw mantienes la pila de la excepción original, pero al usar throw ex ocasiona que la pila original se sobre escriba con la línea de código en que se llamó a esta instrucción.

Manos a la obra, vayamos al código

En este ejemplo vemos que hay una clase llamada Demo con un método privado: DispararError y dos métodos públicos: TareaThrow y TareaThrowEx. Como verán el método DispararError es llamado desde los métodos públicos.

class Demo
{
    public void TareaThrow()
    {
        try
        {
            DispararError();
        }
        catch (Exception)
        {
            throw;
        }
    }

    public void TareaThrowEx()
    {
        try
        {
            DispararError();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void DispararError()
    {
        throw new ApplicationException("Error");
    }
}

NOTA: Este código es solo para demostrar la diferencia entre el throw y el throw ex, no copien y peguen en producción sin estar seguros de su buen funcionamiento.

Ahora pasemos a probar el código, primero ejecutamos el método TareaThrow:

var demo = new Demo();

try
{
    demo.TareaThrow();
}
catch (Exception ex)
{
    Console.WriteLine(ex.StackTrace);
}

Este es el StackTrace que genera el método TareaThrow:

at TryCatchThrowEx.Demo.DispararError() in d:\TryCatchThrowEx\TryCatchThrowEx\DemoThrow.cs:line 33
at TryCatchThrowEx.Demo.TareaThrow() in d:\TryCatchThrowEx\TryCatchThrowEx\DemoThrow.cs:line 15
at TryCatchThrowEx.Program.Main(String[] args) in d:\TryCatchThrowEx\TryCatchThrowEx\Program.cs:line 13

Ahora ejecutamos el método TareaThrowEx:

var demo = new Demo();

try
{
    demo.TareaThrowEx();
}
catch (Exception ex)
{
    Console.WriteLine(ex.StackTrace);
}

Este es el StackTrace que genera el método TareaThrowEx:

at TryCatchThrowEx.Demo.TareaThrowEx() in d:\TryCatchThrowEx\TryCatchThrowEx\DemoThrow.cs:line 27
at TryCatchThrowEx.Program.Main(String[] args) in d:\TryCatchThrowEx\TryCatchThrowEx\Program.cs:line 23

Como se puede observar en los ejemplos anteriores el StackTrace del método TareaThrow muestra que la excepción ocurrió en el método DisparaError lo que es cierto. Ahora en el caso del StackTrace del método TareaThrowEx indica que la excepción ocurrió dentro de ese método ocultando la excepción original.

Entonces, ¿Qué problemas puede traer el uso del throw ex?

  • En producción sera difícil detectar donde ocurrió un error.
  • Aumenta la deuda técnica.
  • Indica que no se hace una correcta revisión de código.

Espera ¿Qué pasa si uso throw new <Exception>?

Usar throw new <Exception> es mejor que el throw ex, siempre y cuando se devuelva la excepción original como Inner Exception. Si no devuelves la excepción como Inner Exception puedes ocultar detalles importantes de la excepción original y se volvería al problema original.

    public void TareaThrowNewException()
    {
        try
        {
            DispararError();
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Información adicional",ex);
        }
    }

Ejecutamos el método TareaThrowNewException:

var demo = new Demo();

try
{
    demo.TareaThrowNewException();
}
catch (Exception ex)
{
    Console.WriteLine(ex.StackTrace);
}

Este es el StackTrace que genera el método TareaThrowNewException:

at TryCatchThrowEx.Demo.DispararError() in d:\TryCatchThrowEx\TryCatchThrowEx\DemoThrow.cs:line 33
at TryCatchThrowEx.Demo.TareaThrow() in d:\TryCatchThrowEx\TryCatchThrowEx\DemoThrow.cs:line 15
at TryCatchThrowEx.Program.Main(String[] args) in d:\TryCatchThrowEx\TryCatchThrowEx\Program.cs:line 13

NOTA: Como mencione en el post ¿Por qué y para qué usas throw? solo se deben relanzar nuevas excepciones si quieres agregar información adicional al error ocurrido.

Conclusión

Usar throw ex está prohibido en cualquier escenario (si alguien conoce de un motivo valido por favor compartalo). Aunque parezcan idénticos, el throw y el throw ex, el resultado generado es diferente. El throw mantiene la pila original, mientras que el throw ex sobre escribe la pila. Al ocultar el origen nos va a ocasionar pérdida de tiempo al tratar de detectar el lugar donde ocurrió la excepción, aumenta la deuda técnica y es un claro indicador que no se realiza una correcta revisión de código.

Si te gusto este post entonces por favor ayúdame a difundirlo y logremos que el conocimiento se expanda, para lograr esto dale me gusta, compártelo en tus redes sociales a tus amigos o suscríbete a mi canal RSS, Gracias :).

Referencias:

Metal Tip:

Este artículo lo escribí escuchando la canción Fear of the Dark de la banda Iron Maiden de Inglaterra, les comparto el enlace.

Happy coding and Stay Heavy lml

Anuncios

4 comentarios en “throw vs throw ex ¿Cuál crees que no debes usar?

    1. Hola Eloy esta muy interesante el articulo y son ciertos los puntos que menciona para crear una excepción, gracias por el aporte.
      Creo que sera motivo de otro post sobre el tema.

      Me gusta

  1. Yo por lo general uso el throw para revertir ciertas cosas del proceso que estaba dentro del bloque try { }catch{}, Pero creo que no necesariamente se sobreescriba el stack trace si se usa debidamente.
    Ya que como la palabra lo dice y es como lo aprendi a usar es para lanzar un exception

    Ejemplo
    ‘//===>SQL Begin Transaction
    try{
    ‘//===>TODO:Tu proceso aqui.

    ‘//===>SQL Commit
    }catch(Exception ex){
    ‘//===>TODO: Agregar aqui todo lo que quieres revertir si tu codigo fallo
    ‘//===>SQL Roll Back Transaction

    throw ex;’//===>Lanzar la exception para que otro try{}cat{} lo maneje.
    }

    /*
    Por lo general solo uso un try{}catch{} en los programas y es el que esta en el main
    cualquier error generado desde cualquier parte del codigo tiene que venir a dar a este main
    si es que no esta dentro de un try{}catch{}
    */

    statict int main(){
    try{
    Application.Run(new FrmMain()); //===>Corre Main form
    }catch(Exception ex){
    ‘//===>Envia correo de error Aqui
    }finally{
    ‘//===>Cierra conexion a la bd Aqui y cierra aplicacion
    Application.Exit();
    }

    }

    Me gusta

  2. Hola MrAlex, al usar throw ex; pierdes la pila del error te sugiero que hagas una prueba y veas el stack trace que se genera y lo compares contra el stacktrace que genera el throw. Otra cosa las transacciones manejales en la lógica de negocio te recomiendo que trabajes con el TransactionScope.

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s