Melhorando o tratamento de exceções no C#
Víctor Fructuoso
Posted on December 2, 2021
Um dos meus principais lemas como programador é:
Se você precisar debugar o código para achar um BUG, é por que o código não está bem escrito.
Neste artigo, abordo três formas de relançar uma exceção e quais as principais diferências entre elas.
Antes de falar sobre a Exception em si, precisamos entender a propriedade mais importante que ela tem... (pausa dramática)
StackTrace
Esta certamente é a propriedade mais importante de qualquer Exception, pois através dela é possível entender toda a "pilha de chamadas" que foi realizada, até o exato ponto onde a exceção foi lançada.
Daí chegamos ao ponto que muitos programadores iniciantes costumam errar...
É muito comum ver tratamentos de erro com algo mais ou menos assim:
_logger.LogError(ex.Message);
Quando isso é feito, estamos jogando fora praticamente toda e qualquer informação que pode nos ajudar a rastrear o erro através do Log.
Neste caso, o ideal seria utilizar algo como o código abaixo:
_logger.LogError(ex, ex.Message);
Neste link temos a documentação oficial da Microsoft com todas as implementações do método de extensão LogError da interface ILogger.
Caso você precise obter os dados da exceção para usar em algum outro local, é preferível ainda usar o ToString(), que entrega o Message concatenado com o StackTrace, fornecendo assim, um detalhamento completo do erro.
O cenário
Para ilustrar as três formas que serão abordadas, vamos entender o seguinte cenário:
A ClasseB possuí o método "OutroMetodo" não implementado.
A ClasseA possui o método "UmMetodo" que chama o método da ClasseB, que por sua vez lançará a exceção "NotImplementedException".
Veremos as três formas de implementar o tratamento de exceção na ClasseA, e o impacto de cada uma delas no Log da aplicação.
throw
Neste caso, a exceção é relançada mantendo o StackTrace completo.
Resultado:
System.NotImplementedException: The method or operation is not implemented.
at ClasseB.OutroMetodo() in Program.cs:line 23
at ClasseA.UmMetodo() in Program.cs:line 12
at Program.<Main>$(String[] args) in Program.cs:line 3
throw ex
Nesta situação a exceção é relançada, mas diferentemente do cenário anterior o StackTrace do que aconteceu antes deste relançamento é descartado.
Em alguns casos isso pode ser útil, para que possamos ocultar algum detalhe do componente ou até mesmo tornar o log menor e mais objetivo.
Notem que neste caso, nenhuma referência a ClasseB é feita.
Resultado:
System.NotImplementedException: The method or operation is not implemented.
at ClasseA.UmMetodo() in Program.cs:line 17
at Program.<Main>$(String[] args) in Program.cs:line 3
CustomException
Neste caso é criado um tipo de exceção customizado, este novo tipo é lançado, passando a exceção original como InnerException.
Desta forma o StackTrace é dividido em dois, tornando mais claro o que aconteceu.
Resultado:
CustomException: Esta é uma exceçao customizada!
---> System.NotImplementedException: The method or operation is not implemented.
at ClasseB.OutroMetodo() in Program.cs:line 23
at ClasseA.UmMetodo() in Program.cs:line 12
--- End of inner exception stack trace ---
at ClasseA.UmMetodo() in Program.cs:line 17
at Program.<Main>$(String[] args) in Program.cs:line 3
Conclusão
Não existe método certo ou método errado, o importante é entender o funcionamento de cada forma de trabalho, para que o detalhamento da exceção seja apresentada da melhor forma possível. Isso fará toda a diferença no momento de identificar um bug, inclusive aquele que você não consegue reproduzir na sua máquina.
Posted on December 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.