TryCatch, como não usar: Dominando a arte da exceção
- #C#
Introdução
O bloco try-catch é uma estrutura de controle de fluxo que permite lidar com exceções em C#. Uma exceção é um evento anormal ou inesperado que ocorre durante a execução de um programa, como por exemplo, uma divisão por zero, uma tentativa de acessar um índice inválido de um array, ou uma conversão inválida de tipos. Quando uma exceção é lançada (throw), o fluxo normal do programa é interrompido e o controle é passado para o bloco catch mais próximo que pode tratar aquela exceção. Repare bem no fato de que uma exceção é lançada, o que informa o programador sobre o que ocorreu, mas demanda processamento. O bloco try contém o código que pode gerar uma exceção, e o bloco catch contém o código que executa quando uma exceção é capturada.
O uso do bloco try-catch é uma boa prática de programação, pois permite evitar que o programa termine abruptamente ou produza resultados incorretos quando ocorre uma exceção, ou as vezes, pode tornar uma exceção feia ou não informativa mais adequada para o usuário, seja o usuário final ou o programador.
try
{
//Codigo...
Objeto.Operacao(); //Pode talvez ocorrer um erro aqui.
Console.WriteLine($"Operação concluida com sucesso!");
}
catch (Exception ex)
{
Console.WriteLine("Ops, algo deu errado: " + ex.Message); //Tratamento genérico do possível erro. Inclusive esse catch poderia ser usado para logar o erro. Muito útil, recomendo ;)
}
No entanto, o bloco try-catch não deve ser usado de forma indiscriminada ou inadequada, pois isso pode trazer alguns problemas e desvantagens. Neste artigo, vamos ver alguns exemplos de como não usar o bloco try-catch em C#, e quais são as alternativas mais recomendadas.
Cuidado com os atalhos!
Usar o `try...catch` como um atalho pode entregar sua sprint a tempo, mas produz um código não muito bom.
Valores nulos
Para evitar a checagem de valores nulos pode mascarar problemas e comprometer a qualidade do seu código.
Um exemplo:
try
{
var nome = Console.ReadLine();
var idade = int.Parse(nome); // Erro se nome for nulo!
Console.WriteLine($"Olá, {nome}, você tem {idade} anos!");
}
catch (Exception ex)
{
Console.WriteLine("Ops, algo deu errado: " + ex.Message);
}
Neste exemplo, o código tenta converter a entrada do usuário (`nome`) para um inteiro (`idade`). Se o usuário digitar um texto, o código lançará uma exceção. O `catch` captura a exceção e informa o problema, mas não resolve a causa: o valor nulo em `nome`.
Evite usar o `try...catch` para problemas que podem ser facilmente detectados e corrigidos com antecedência. Utilize a checagem de valores nulos antes de operações críticas para evitar exceções desnecessárias e tornar seu código mais robusto e eficiente.
if(nome != null)// Mais conciso, elegante, rápido, limpo e simples
var idade = int.Parse(nome);
Console.WriteLine($"Olá, {nome}, você tem {idade} anos!");
Ao usar a checagem de nulos, você direciona o `try...catch` para lidar com exceções realmente inesperadas, como falhas de hardware ou erros de rede, tornando seu código mais preciso e eficaz.
Usando Try-Catch como Controle de Fluxo
Esse também é um uso tentador do try-catch.
"Ah, vou tentar seguir por aqui, mas se qualquer coisa acontecer, ele cai no catch e segue". Esse tipo de pensamento faz sentido técnico? Sim, mas não é o mais indicado. Demonstra pouco entendimento do programa e de lógica em geral. Em teoria, dever-se-ia saber tudo o que pode acontecer com o fluxo. Assim, o try-catch deveria ser usado apenas em situações realmente inesperadas.
try
{
// Operação que pode lançar uma exceção
AbrirArquivo("arquivo.txt");
}
catch (FileNotFoundException ex)
{
// Tentativa de corrigir o problema
CriarArquivo("arquivo.txt");
}
Neste exemplo, o bloco Try-Catch é usado como uma forma de controle de fluxo, tentando corrigir o problema de um arquivo não encontrado criando-o. Embora isso possa resolver temporariamente o problema, não é uma solução ideal, pois o código pode capturar exceções não relacionadas à ausência do arquivo, mascarando assim outros problemas potenciais no sistema.
Conclusão
Nos casos citados, o bloco Try-Catch está sendo usado de forma inadequada, não abordando adequadamente as causas raiz das exceções e potencialmente introduzindo mais complexidade e fragilidade no código.
O `try...catch` é uma ferramenta poderosa, mas não um substituto para a atenção aos detalhes e a escrita de código defensivo.
Use a checagem de valores nulos para evitar exceções desnecessárias e aumentar a robustez do seu código.
Reserve o `try...catch` para lidar com exceções realmente inesperadas.
Ao seguir estas dicas, você se tornará um mestre do `try...catch`, capaz de lidar com erros com elegância e garantir que seu código funcione como um relógio.
Um adendo
Há também a estrutura Try-Catch-Finally, mas o Finally não foi abordado pois seria interessante um post só para ele.
Referências
É simples procurar por um vídeo ou post explicando como a estrutura try-catch funciona, aqui então vão duas recomendações um pouco mais avançadas sobre o assunto:
Uma explicação mais completa sobre o assunto, interessante para entender um pouco alem do básico sobre try-catchs em C#
Try. Finally. If. Not. Null. (A tradução do chrome para português pode ajudar)
Sugiro altamente a leitura de vários posts desse autor, nesse em específico ele discorre brevemente sobre valores nulos e os problemas que causam no código associado a prática de usar try-catch com eles. O autor sempre escreve sobre Java mas serve perfeitamente para C#, ja que o assunto é orientação a objetos em geral.