English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Tratamento de Exceções do C#

Aqui, você aprenderá a usar os blocos try, catch e finally para lidar com exceções no C#.

É necessário lidar com exceções no aplicativo para evitar que o programa travasse e para resultados inesperados, registrar exceções e continuar executando outras funcionalidades. O C# fornece suporte integrado para o tratamento de exceções usando os blocos try, catch e finally.

Sintaxe:

try
{
    // Colocar o código aqui pode gerar uma exceção
}
catch
{
    // Trate as exceções aqui
}
finally
{
    // Código de limpeza final
}

Bloco try:Qualquer código suspeito que possa gerar uma exceção deve ser colocado dentro de um bloco try{ }. Durante a execução, se ocorrer uma exceção, o fluxo de controle saltará para o primeiro bloco catch correspondente.

catch Bloco:O bloco catch é um bloco de tratamento de exceções onde você pode executar algumas operações, como registrar e auditar exceções. O bloco catch aceita um parâmetro do tipo de exceção, que você pode usar para obter detalhes da exceção.

finally Bloco:O bloco finally sempre será executado, independentemente de uma exceção ser lançada ou não. Normalmente, o finally deve ser usado para liberar recursos, como fechar qualquer fluxo ou objeto de arquivo aberto no bloco try.

Se você inserir caracteres não numéricos, o seguinte pode gerar uma exceção.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Enter a number: ");
        var num = int.Parse(Console.ReadLine());
        Console.WriteLine($"Squre of {num} is {num"); * num");
    }
}

Para lidar com possíveis exceções no exemplo acima, envolva o código em um bloco try e, em seguida, lidar com a exceção no bloco catch, conforme mostrado a seguir.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Enter a number: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"Squre of {num} is {num"); * num");
        }
        catch
        {
            Console.Write("Error occurred.");
        }
        finally
        {
            Console.Write("Re");-tente novamente com um número diferente.");
        }
    }
}

No exemplo acima, estamos empacotando este código em um bloco try. Se ocorrer uma exceção dentro do bloco try, o programa saltará para o bloco catch. Dentro do bloco catch, mostraremos uma mensagem para informar o usuário sobre o erro, e dentro do bloco finally, mostraremos uma mensagem sobre as operações realizadas após a execução do programa.

O bloco try deve ser seguido por catch ou finally ou ambos os segmentos. Se o bloco try não usar catch ou finally, será gerado um erro de compilação.

Em um cenário ideal, o bloco catch deve conter um parâmetro de classe de exceção interna ou personalizada para obter detalhes de erro. A seguir, inclui o parâmetro type do Exception que captura todos os tipos de exceções.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Enter a number: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"Squre of {num} is {num"); * num");
        }
        catch(Exception ex)
        {
            Console.Write("Error info:"); + ex.Message);
        }
        finally
        {
            Console.Write("Re");-tente novamente com um número diferente.");
        }
    }
}

Filtros de exceção

Você pode usar múltiplos blocos catch com diferentes tipos de parâmetros de exceção. Isso é chamado de filtro de exceção. Quando você deseja lidar com diferentes tipos de exceções de maneiras diferentes, o filtro de exceção é muito útil.

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Por favor, insira um número para dividir 100: ");
        
        try
        {
            int num = int.Parse(Console.ReadLine());
            int result = 100 / num;
            Console.WriteLine("100 / {0} = {1}
        }
        catch(DivideByZeroException ex)
        {
            Console.Write("Não pode ser dividido por zero. Por favor, tente novamente.");
        }
        catch(InvalidOperationException ex)
        {
            Console.Write("Operação inválida. Por favor, tente novamente.");
        }
        catch(FormatException  ex)
        {
            Console.Write("Não é um formato válido. Por favor, tente novamente.");
        }
        catch(Exception  ex)
        {
            Console.Write("Ocorreu um erro! Por favor, tente novamente.");
        }
    }
}

No exemplo acima, especificamos múltiplos blocos catch com diferentes tipos de exceções. Podemos exibir mensagens apropriadas ao usuário com base no erro, para que o usuário não repita o mesmo erro novamente.

Atenção:
Não é permitido ter múltiplos blocos catch com o mesmo tipo de exceção. O bloco catch com o tipo de exceção base deve ser o último bloco.

Bloco catch inválido

Não é permitido usar um bloco catch sem parâmetros e um bloco catch com parâmetro Exception na mesma declaração try..catch, pois eles executam a mesma operação.

try
{
    //código que pode gerar exceção
}
catch //Não é permitido ter tanto catch quanto catch(Exception exceção)
{ 
    Console.WriteLine("Ocorreu uma exceção");
}
catch(Exception ex) //Não é permitido ter tanto catch quanto catch(exceção exceção)
{
    Console.WriteLine("Ocorreu uma exceção");
}

Além disso, o bloco catch sem parâmetros catch {} ou o bloco catch genérico catch (Exception ex){} devem ser os últimos blocos. Se houver outro bloco catch após o bloco catch {} ou catch (Exception ex), o compilador emitirá um erro.

    Exemplo: captura catch inválida

try
{
    //código que pode gerar exceção
}
catch
{ 
    // Este bloco de captura deve ser o último bloco
}
catch (NullReferenceException nullEx)
{
    Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
    Console.WriteLine(inEx.Message);
}

bloco finally

O bloco finally é opcional e deve estar após o bloco try ou catch. O bloco finally será executado sempre, independentemente de uma exceção ter ocorrido ou não. O bloco finally geralmente é usado para código de limpeza, como lidar com objetos não gerenciados.

    Exemplo: bloco finally

static void Main(string[] args)
{
    FileInfo file = null;
    try
    {
        Console.Write("Digite o nome do arquivo para escrever: ");
        string fileName = Console.ReadLine();
        file = new FileInfo(fileName);
        file.AppendText("Hello World!")
    }
    catch(Exception ex)
    {
        Console.WriteLine("Ocorreu um erro: {0}", ex.Message);
    }
    finally
    {
        // Aqui, limpe o objeto arquivo;
        file = null;
    }
}
finally não pode usar múltiplos blocos. Além disso, o bloco finally não pode conter palavras-chave return, continue ou break. Não permite que o controle saia do bloco finally.

try aninhado-catch

C# permite try aninhado-No bloco catch. Quando você usa try aninhado-No bloco catch, a exceção será capturada no primeiro bloco correspondente após o bloco try onde ocorreu a exceção catch.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch
        {
            Console.WriteLine("catch interno");
        }
    }
    catch
    {
        Console.WriteLine("catch externo");
    }
}
Saída:
catch bloco interno

No exemplo acima, o bloco catch executará um bloco interno porque é o primeiro bloco a lidar com todos os tipos de exceções.

Se não houver bloco catch interno que coincida com o tipo de exceção lançada, o controle fluirá para o bloco catch externo até encontrar o filtro de exceção apropriado. Veja o exemplo a seguir.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch(NullReferenceException ex)
        {
            Console.WriteLine("catch interno");
        }
    }
    catch
    {
        Console.WriteLine("catch externo");
    }
}
Saída:
catch externo

No exemplo acima, será gerada uma exceção de tipo DivideByZeroException. Como o bloco catch interno apenas trata NullReferenceTypeException, o bloco catch externo o tratará.