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 final contém código que é executado independentemente de uma exceção ser lançada ou não no bloco, como liberar try recursos alocados try no bloco. 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 como o filtro de exceção, a menos que você saiba como lidar com todas as exceções que possam ser lançadas no try bloco ou tenha incluído uma throw instrução no final do 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 catch bloco é usado para adicionar uma entrada a um log de erros antes de lançar novamente 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 catch específica corresponde apenas quando essa condição for 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 finally bloco pode ser usado para liberar recursos como fluxos de arquivos, conexões de banco de dados e identificadores gráficos sem esperar que o coletor de lixo no tempo de execução finalize os objetos.

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

Consulte também