Partilhar via


Tratamento de exceções (Guia de programação em C#)

Um bloco try é usado por programadores C# para particionar código que pode ser afetado por uma exceção. Os blocos de captura associados são usados para lidar com quaisquer exceções resultantes. Um bloco finally contém código que é executado independentemente de uma exceção ser lançada ou não no bloco try, como liberar recursos que foram alocados no bloco try. Um try bloco requer um ou mais blocos associados catch , ou um finally bloco, ou ambos.

Os exemplos a seguir mostram uma try-catch instrução, uma try-finally instrução e uma try-catch-finally instrução.

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.
}

Um try bloco sem um catch ou finally bloco causa um erro de compilador.

Blocos de captura

Um catch bloco pode especificar o tipo de exceção a capturar. A especificação de tipo é chamada de filtro de exceção. O tipo de exceção deve ser derivado de Exception. Em geral, não especifique Exception para o filtro de exceção, a menos que saiba como lidar com todas as exceções que possam ser lançadas no bloco try, ou tenha incluído uma instrução throw no final do seu bloco catch.

Vários catch blocos com diferentes classes de exceção podem ser encadeados. Os catch blocos são avaliados de cima para baixo em seu código, mas apenas um catch bloco é executado para cada exceção lançada. O primeiro catch bloco que especifica o tipo exato ou uma classe base da exceção lançada é executado. Se nenhum catch bloco especificar uma classe de exceção correspondente, um catch bloco que não tenha nenhum tipo será selecionado, se um estiver presente na instrução. É importante posicionar catch os blocos com as classes de exceção mais específicas (ou seja, as mais derivadas) primeiro.

Detete exceções quando as seguintes condições forem verdadeiras:

  • Você tem uma boa compreensão do motivo pelo qual a exceção pode ser lançada e pode implementar uma recuperação específica, como solicitar que o usuário insira um novo nome de arquivo quando capturar um FileNotFoundException objeto.
  • Você pode criar e lançar uma nova exceção mais 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);
        }
    }
    
  • Você deseja lidar parcialmente com uma exceção antes de passá-la para mais manipulação. No exemplo a seguir, um bloco catch é usado para adicionar uma entrada a um registo de erros antes de reatirar a exceção.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

Você também pode especificar filtros de exceção para adicionar uma expressão booleana a uma cláusula catch. Os filtros de exceção indicam que uma cláusula de captura específica corresponde apenas quando a condição é verdadeira. No exemplo a seguir, ambas as cláusulas catch usam a mesma classe de exceção, mas uma condição extra é verificada para criar uma mensagem de erro 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);
    }
}

Um filtro de exceção que sempre retorna false pode ser usado para examinar todas as exceções, mas não processá-las. Um uso típico é registrar exceções:

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;
    }
}

O LogException método sempre retorna false, nenhuma catch cláusula usando esse filtro de exceção corresponde. A cláusula catch pode ser geral, usando System.Exception, e cláusulas posteriores podem processar classes de exceção mais específicas.

Finalmente Blocos

Um finally bloco permite limpar ações que são executadas em um try bloco. Se presente, o finally bloco é executado por último, após o try bloco e qualquer bloco correspondente catch . Um finally bloco sempre é executado, quer uma exceção seja lançada ou um catch bloco correspondente ao tipo de exceção seja encontrado.

O bloco finally pode ser usado para liberar recursos como fluxos de arquivos, conexões de banco de dados e identificadores gráficos sem esperar a finalização dos objetos pelo coletor de lixo no tempo de execução.

No exemplo a seguir, o finally bloco é usado para fechar um arquivo que é aberto no try bloco . Observe que o estado do identificador de arquivo é verificado antes que o arquivo seja fechado. Se o try bloco não puder abrir o arquivo, o identificador de arquivo ainda terá o valor null e o bloco não tentará finally fechá-lo. Em vez disso, se o arquivo for aberto com êxito no try bloco , o finally bloco fechará o arquivo aberto.

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();
}

Especificação da linguagem C#

Para obter mais informações, consulte Exceptions and The try statement na C# Language Specification. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.

Ver também