Manipulação de Erros em C#: try/catch e além
A manipulação de erros é um dos componentes-chave de um software confiável. Em C#, o mecanismo de exceções (exceptions) é usado para esse fim. A aplicação correta das construções try, catch e finally permite não apenas evitar o encerramento abrupto do programa, mas também tornar o código mais legível e previsível. Neste artigo, abordaremos os fundamentos da manipulação de exceções, as melhores práticas e os recursos avançados que a plataforma .NET oferece.
1. Bloco básico try/catch/finally
A principal ferramenta de manipulação de erros em C# é o bloco try-catch-finally. Sua sintaxe é intuitiva:
- try — contém o código que pode lançar uma exceção.
- catch — captura e trata a exceção.
- finally — é executado sempre, independentemente de ter ocorrido uma exceção. É usado para liberar recursos (fechar arquivos, conexões com o banco de dados).
Vamos considerar um exemplo simples — divisão por zero:
using System;
class Program{ static void Main() { try { int a = 10; int b = 0; int result = a / b; // Uma exceção ocorrerá aqui Console.WriteLine($"Resultado: {result}"); } catch (DivideByZeroException ex) { Console.WriteLine($"Erro: {ex.Message}"); } finally { Console.WriteLine("Bloco finally executado."); } }}Saída do programa:
Erro: Tentativa de divisão por zero.Bloco finally executado.Observe: se você não especificar um tipo de exceção específico, o bloco catch capturará todas as exceções. Isso pode ser conveniente, mas geralmente é considerado uma má prática, pois oculta problemas reais.
2. Tipos de exceções e sua hierarquia
Em C#, todas as exceções herdam da classe base System.Exception. As mais usadas são:
SystemException— classe base para exceções do sistema.NullReferenceException— acesso a um objeto que énull.IndexOutOfRangeException— acesso fora dos limites de um array.InvalidOperationException— chamada de um método em um estado inválido.ArgumentExceptione seus herdeiros (ArgumentNullException,ArgumentOutOfRangeException) — argumentos de método inválidos.
Você pode capturar vários tipos de exceções em um único bloco catch (a partir do C# 6):
try{ // código}catch (ArgumentNullException ex) when (ex.ParamName == "userId"){ Console.WriteLine("O parâmetro userId não deve ser null.");}catch (InvalidOperationException ex){ Console.WriteLine($"Operação inválida: {ex.Message}");}catch (Exception ex) when (Log(ex, "Erro desconhecido")){ // Filtro de exceção — o bloco é executado apenas se a condição for verdadeira throw; // Relança a exceção adiante}Os filtros de exceção (palavra-chave when) permitem um controle mais flexível da lógica de tratamento, sem perder a pilha de chamadas.
3. Geração de exceções personalizadas
Às vezes, as exceções padrão não são suficientes. Você pode criar sua própria classe de exceção, herdando de Exception:
public class InvalidAgeException : Exception{ public int Age { get; }
public InvalidAgeException(int age, string message) : base(message) { Age = age; }
public InvalidAgeException(int age, string message, Exception inner) : base(message, inner) { Age = age; }}Agora