Introducción al control de errores: try - catch - finally

En ocasiones es imprescindible manejar el comportamiento de nuestra aplicación cuando surge un error.
Por ejemplo debemos exigir que se cierre un DataReader si se produce un error, que se cierre un fichero XML si surge un error de lectura, o que se controle una llamada a un WebService al que no tenemos acceso ninguno.

Así pues, el objetivo de este artículo es mostrar el uso básico de los comandos try, catch y finally.

Por ejemplo vamos a controlar si surge algún error cuando enviamos un Email mediante nuestro código C# (error que, dicho sea de paso, sucede a menudo). Recordando de nuestro artículo de "envío de emails con ASP.NET":

    MailMessage Email = new MailMessage(Origen, Destino, Asunto, Mensaje);
    SmtpClient smtp = new SmtpClient();
    try
    {
        smtp.Send(Email);
    }
    catch (Exception ex)
    {
        Label1.Text = ex.Message;
    }


Como vemos, tratamos de enviar un mensaje, y si nos da error lo mostraremos en nuestro Label (que suponemos está en nuestra página .aspx). De modo que dentro de "try" colocaremos el código que queremos vigilar y dentro del "catch" diremos lo que queremos hacer si sucede una excepción.

Cuando estemos más avanzados en el pequeño mundo de la captura de errores, veremos que se pueden anidar tantos catch como queramos, poniéndoles a cada uno como parámetro el tipo de excepción que queramos controlar. Pero esto no lo vamos a explicar en este artículo, con la idea de mantenernos en un nivel básico/ de iniciación.

En cuanto al "finally", es el comando al que se acudirá siempre, tanto si sucede un error como si no. Por ejemplo:

    MailMessage Email = new MailMessage(Origen, Destino, Asunto, Mensaje);
    SmtpClient smtp = new SmtpClient();
    try
    {
        smtp.Send(Email);
    }
    catch (Exception ex)
    {
        Label1.Text = ex.Message;
    }
    finally
    {
       Label2.Text = "Ya hemos hecho el intento de envío de mensaje";
    }

Si no sucediera un error, de forma que el mail se mande correctamente, al acabar el envío llegaremos al finally y escribiremos sobre la Label2... pero si sucede un error, cuando lo hayamos tratado en el catch también llegaremos al finally y escribiremos sobre la Label2.

El finally es muy útil en los ejemplos que hemos comentado al inicio. Por ejemplo si trabajamos con un DataReader, pondremos un árbol try - catch - finally en el que el catch controlaría los errores y el finally se encargaría de cerrar el DataReader, de modo que éste quedaría cerrado surgiera o no un error.

Para finalizar, es importante destacar que no hay que usar try - catch - finally en todos los sitios, ni imponer el control de errores de forma genérica sobre numerosas líneas de código. Hay que darse cuenta de que al usarlos estamos utilizando una vigilancia exhaustiva de todo lo que sucede, por lo que gastamos recursos y empeorará la eficiencia de nuestra aplicación.

Por tanto se recomienda usarlos sólo cuando haga falta y tratando de utilizar otros remedios menos gastadores. Por ejemplo, en lugar de hacer esto:

        try
        {
            resultado = a / b;
        }
        catch
        {
            // Si ha dado error es que b = 0. Le daremos el valor de 0 a resultado, aunque obviamente no vale eso.
            resultado = 0;
        }


hay que hacer esto:

        if (b != 0)
            resultado = a / b;
        else
            resultado = 0;