TOC

This article is currently in the process of being translated into Spanish (~99% done).

Advanced topics:

Exception handling

En cada programa, las cosas a veces van mal. Con C#, somos afortunados con un buen compilador, el cual nos ayudará a prevenir algunos de los errores más comunes. Obviamente no puede ver cada error que puede sucedar, y es esos casos, el ambiente .NET lanzará una excepción, para decirnos que algo salio mal. En un capítulo incial, sobre arreglos, describpi como obtendriamos una excepción si intentabamos poner demasiados elementos en un arreglo. Traigamos el ejemplo:

using System;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
static void Main(string[] args)
{
    int[] numbers = new int[2];

    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
    Console.ReadLine();
}
    }
}

Está bién, trate de correr este ejemplo, verá de lo que hablo. ¿Ve que estamos haciendo mal? Hemos definido un arreglo de enteron son espacio para 2 elementos, aún así intentamos usar 3 espacios en el. Obviamente, esto nos lleva a un error, el cual verá si intenta correr este ejemplo. Cuando corre dentro de Visual Studio, el IDE nos da algunas opciones para la excepción, pero si intenta ejecutar el programa ejecutando el archivo EXE, obtendrá un asqueroso error. Si sabe que un error puede ocurrir, deberia manejarlo. Este es donde las excepciones son usadas. Aquí está una versión ligeramente modificada del código de arriba:

int[] numbers = new int[2];
try
{
    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
}
catch
{
    Console.WriteLine("Something went wrong!");
}
Console.ReadLine();

Permítame presentarle al mejor amigo cuando se trata de manejo de errores: el bloque try..catch. Intente correr el programa ahora, vea la diferencia - en vez de que Visual Studio o Windows nos digan que un problema seria ocurrió, podemos contar nuestra propia historia. ¿Pero no sería bonito si pudieramos decir lo que sucedió? No hay problema:

catch(Exception ex)
{
    Console.WriteLine("An error occured: " + ex.Message);
}

Como puede ver, hemos agregado algunas cosas a la declaración catch. Ahora decimos cual excepción queremos atrapar, en este caso la base de todas las excepciones, la Exception. Al hacerlo así, obtenemos alguna información acerca del problema que causó la excepción, y al desplegar la propiedad Message, obtenemos una descripción entendible del problema.

Como dije, Exception es el tipo más general excepciones. Las reglas de manejo de excepciones nos dicen que siempre debemos usar el tipo de excepción menos general, y en este caso, realmente sabemos el tipo exacto de excepción generada por nuestro código. ¿Cómo? Por que Visual Studio nos dijo cuando no la manejamos. Si lo duda, la documentación usualmente describe que excepciones puede lanzar un método. Otra forma de encontrar es usando la clase Exception para que nos diga - cambie la línea de salida a esto:

Console.WriteLine("An error occured: " + ex.GetType().ToString());

El resultado es, como era esperado, Excepción de Índice fuera de Rango. Deberíamos entonces manejar esta excepción, pero nada nos previene de manejar más de una excepción. En algunas situaciones usted deseará hacer cosas diferentes, dependiendo de cual excepción es lanzada. Simplemente cambie nuestro bloque catch al siguente:

catch(IndexOutOfRangeException ex)
{
    Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
    Console.WriteLine("Some sort of error occured: " + ex.Message);
}

Como puede ver, buscamos primero la excepción por índice fuera de rango. Si lo hacemos de otra forma, el bloque catch con la clase Exception la capturará, por que todas las excepciones se derivan de ella. Así en otras palabras, debe usar las excepciones más específicas primero.

Una cosa adicional que debe saber respecto a excepciones es el bloque finally. el bloque finally puede ser agregado a un conjunto de bloques catch, o ser usado exclusivamente, dependiendo de sus necesidades. El código en el bloque finally siempre es ejecutado - con o sin excepción. Es un buen lugar si necesita cerrar referencias de archivo o liberar objetos que no necesitará más. Ya que nuestro ejemplo ha sido muy simple hasta ahora, no hemos tenido la necesidad de realizar ninguna limpieza realmente, ya que el colector de basura maneja esto. Pero como es probable que corra en situaciones donde necesite el bloque finally, aquí está una versión extendida de nuestro ejemplo:

int[] numbers = new int[2];
try
{
    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
}
catch(IndexOutOfRangeException ex)
{
    Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
    Console.WriteLine("Some sort of error occured: " + ex.Message);
}
finally
{
    Console.WriteLine("It's the end of our try block. Time to clean up!");
}
Console.ReadLine();

Si usted corre el código, verá que ambos el primer bloque de excepción y el bloque finally son ejecutados. Si remueve la línea que agrega el número 42 al arreglo, verá que solamente el bloque finally es alcanzado.

Otra parte importante que debe saber acerca de las excepciones, es como impactan los métodos en los cuales ocurren las excepciones. No todas las excepciones no manejadas son fatales para su aplicación, pero cuando lo son, no debe esperar que el código restante del método se ejecute. Por otro lado, si maneja la excepción, solamente las líneas después del bloque try serán ejecutadas. En nuestro ejemplo, el ciclo que despliega los valores del arreglo nunca es alcanzado, por que el bloque try va directamente a los bloques catch/finally una vez que la excepción es lanzada. Sin embargo, la última línea, donde leemos desde la consola para prevenir la aplicación de terminar inmediatemente, es alcanzada. Debe tener esto en cuenta siempre que construye bloques try.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!