Compartir a través de


Control de excepciones (Guía de programación de C#)

Los programadores de C# usan un bloque try para crear particiones de código que podría verse afectado por una excepción. Los bloques catch asociados se usan para controlar las excepciones resultantes. Un bloque finally contiene código que se ejecuta si se produce o no una excepción en el try bloque, como liberar recursos asignados en el try bloque. Un try bloque requiere uno o varios bloques asociados catch , o un finally bloque, o ambos.

En los siguientes ejemplos, se muestra una sentencia try-catch, una sentencia try-finally y una sentencia try-catch-finally.

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

Un try bloque sin un catch o finally provoca un error de compilador.

Bloques catch

Un catch bloque puede especificar el tipo de excepción que se va a detectar. La especificación de tipo se denomina filtro de excepciones. El tipo de excepción debe derivarse de Exception. En general, no especifique Exception como el filtro de excepciones a menos que sepa cómo controlar todas las que puedan producirse en el bloque try o que haya incluido una instrucción throw al final del bloque catch.

Se pueden encadenar varios catch bloques con clases de excepción diferentes. Los catch bloques se evalúan de arriba abajo en el código, pero solo se ejecuta un catch bloque para cada excepción que se produce. El primer catch bloque que especifica el tipo exacto o una clase base de la excepción iniciada se ejecuta. Si ningún catch bloque especifica una clase de excepción coincidente, se selecciona un catch bloque que no tiene ningún tipo, si hay uno presente en la instrucción . Es importante colocar primero bloques catch con clases de excepción más específicas (es decir, las más derivadas).

Detectar excepciones cuando se cumplen las condiciones siguientes:

  • Tiene una buena comprensión de por qué se puede producir la excepción y puede implementar una recuperación específica, como pedir al usuario que escriba un nuevo nombre de archivo al capturar un FileNotFoundException objeto.
  • Puede crear y lanzar una nueva excepción más específica.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • Quiere controlar parcialmente una excepción antes de pasarla para aumentar su control. En el ejemplo siguiente, se usa un catch bloque para agregar una entrada a un registro de errores antes de volver a iniciar la excepción.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

También puede especificar filtros de excepción para agregar una expresión booleana a una cláusula catch. Los filtros de excepción indican que una cláusula catch específica coincide solo cuando esa condición es verdadera. En el ejemplo siguiente, ambas cláusulas catch usan la misma clase de excepción, pero se comprueba una condición adicional para crear un mensaje de error diferente:

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

Un filtro de excepción que siempre devuelve false se puede usar para examinar todas las excepciones, pero no procesarlas. Un uso típico es registrar excepciones:

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

El LogException método siempre devuelve false, ninguna catch cláusula que use este filtro de excepciones coincide. La cláusula catch puede ser general, usando System.Exception, y cláusulas posteriores pueden procesar clases de excepciones más específicas.

Bloques Finally

Un finally bloque le permite limpiar las acciones que se realizan en un try bloque. Si está presente, el finally bloque se ejecuta en último lugar, después del try bloque y de cualquier bloque coincidente catch . Un finally bloque siempre se ejecuta, tanto si se produce una excepción como si se encuentra un catch bloque que coincida con el tipo de excepción.

Los bloques finally pueden usarse para liberar recursos como secuencias de archivo, conexiones de base de datos y controladores de gráficos sin necesidad de esperar a que el recolector de elementos no utilizados en tiempo de ejecución finalice los objetos.

En el ejemplo siguiente, el finally bloque se usa para cerrar un archivo que se abre en el try bloque . Observe que el estado del identificador de archivo se comprueba antes de cerrar el archivo. Si el try bloque no puede abrir el archivo, el identificador de archivo todavía tiene el valor null y el finally bloque no intenta cerrarlo. En su lugar, si el archivo se abre correctamente en el try bloque, el finally bloque cierra el archivo abierto.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

Especificación del lenguaje C#

Para obtener más información, vea Excepciones y la instrucción try en la especificación del lenguaje C#. La especificación del lenguaje es el origen definitivo de la sintaxis y el uso de C#.

Consulte también