Compartilhar 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 catch associados são usados para lidar com quaisquer exceções resultantes. Um bloco finally contém o código que é executado, seja lançada uma exceção ou não no bloco try, como liberação de recursos 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 do compilador.

Blocos catch

Um bloco catch pode especificar o tipo de exceção a ser capturado. 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 como o filtro de exceção, a menos que você saiba como lidar com todas as exceções que podem ser lançadas no bloco try ou que você tenha incluído uma instrução throw no final do bloco catch.

Vários catch blocos com classes de exceção diferentes podem ser encadeados juntos. Os catch blocos são avaliados de cima para baixo em seu código, mas apenas um catch bloco é executado para cada exceção gerada. 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 tem nenhum tipo será selecionado, se houver um presente na instrução. É importante posicionar catch blocos com as classes de exceção mais específicas (ou seja, as mais derivadas) primeiro.

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

  • Você tem uma boa compreensão de por que a exceção pode ser gerada e você pode implementar uma recuperação específica, como solicitar que o usuário insira um novo nome de arquivo ao capturar um FileNotFoundException objeto.
  • Você pode criar e lançar uma exceção nova e 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 tratar parcialmente uma exceção antes de passá-la para mais tratamento. No exemplo a seguir, o bloco catch é usado para adicionar uma entrada no log de erros antes de relançar 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 booliana a uma cláusula catch. Filtros de exceção indicam que uma cláusula catch específica corresponde somente quando essa 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 cláusula catch corresponde a este filtro de exceção. A cláusula catch pode ser geral, usando System.Exceptione cláusulas posteriores podem processar classes de exceção mais específicas.

Blocos Finally

Um bloco finally permite que você limpe as ações que são realizadas em um bloco try. Se estiver presente, o finally bloco será executado por último, após o try bloco e qualquer bloco correspondente catch . Um finally bloco sempre é executado, se uma exceção é lançada ou um catch bloco que corresponde ao tipo de exceção é encontrado.

O bloco finally pode ser usado para liberar recursos, como fluxos de arquivos, conexões de banco de dados e identificadores de gráficos, sem esperar que o coletor de lixo no runtime finalize os objetos.

No exemplo a seguir, o finally bloco é usado para fechar um arquivo aberto no try bloco. Observe que o estado do identificador de arquivo é verificado antes do arquivo ser fechado. Se o try bloco não puder abrir o arquivo, o identificador de arquivo ainda terá o valor null e o finally bloco não tentará 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 Exceções e a instrução Try na Especificação da Linguagem C#. A especificação de idioma é a fonte definitiva para a sintaxe e o uso de C#.

Consulte também