C# - Diferença entre throw e throw ex
Apresentando as diferenças entre throw e throw ex no tratamento de exceções na linguagem c#. |
Quando tratamos exceções na linguagem C# geralmente usamos o bloco try/catch/finally e podemos encontrar diversos exemplos que usam duas abordagens :
try
{
//algum código
}
catch
{
throw;
}
|
try
{
//algum código
}
catch (Exception ex)
{
throw ex;
}
|
Vamos entender o que acontece em cada abordagem:
1 - lançando um throw
Quando você lança apenas um throw está repassando a mesma exceção para frente e, dessa forma, outro trecho de código poderá capturar e saber o que vai fazer com a exceção original retendo todas as informações necessárias com o stack trace.
2 - lançando um throw ex
Quando você lança um throw ex, você esta parando a exceção ali e após fazer alguma operação, você lança outra exceção a partir dali. Dessa forma a informação de onde veio a exceção original é perdida. Tudo se passa como se tivesse ocorrido uma nova exceção.
Agora vamos usar um exemploprático para você perceber como isso é importante e porque você deve dar preferência usar a primeira opção.
Recursos Usados neste artigo :
Criando o projeto Console
Crie um projeto Console Application e inclua o seguinte código no arquivo Program.cs :
1 - lançando um throw
using System;
namespace CShp_Exceptions
{
class Program
{
static void Main(string[] args)
{
Funcionario funci = new Funcionario();
Console.WriteLine(funci.GetDetalhes());
Console.Read();
}
class Funcionario
{
public String GetDetalhes()
{
try
{
Departamento depto = new Departamento();
return depto.GetDepartmentos();
}
catch (Exception ex)
{
Console.WriteLine("---Registra Stack Trace para exceções----");
Console.WriteLine(ex.StackTrace.ToString());
Console.WriteLine("---Registra o nome do método na qual a exceção ocorreu---");
Console.WriteLine(ex.TargetSite.ToString());
}
return "";
}
}
class Departamento
{
public String GetDepartmentos()
{
try
{
DividirPorZero();
return "Método GetDepartmentos foi chamado";
}
catch(Exception ex)
{
throw;
}
}
//estamos gerando uma exception
public void DividirPorZero()
{
throw new DivideByZeroException();
}
}
}
}
|
Neste código estamos gerando uma exceção do tipo divisão por zero e usando um try/catch lançado apenas throw.
Veja o resultado obtido:
Observe que todos os métodos foram registrados na pilha; inclusive o método DividirPorZero() que causou a exceção.
2 - lançando um throw ex
using System;
namespace CShp_Exceptions
{
class Program
{
static void Main(string[] args)
{
Funcionario funci = new Funcionario();
Console.WriteLine(funci.GetDetalhes());
Console.Read();
}
class Funcionario
{
public String GetDetalhes()
{
try
{
Departamento depto = new Departamento();
return depto.GetDepartmentos();
}
catch (Exception ex)
{
Console.WriteLine("---Registra Stack Trace para exceções----");
Console.WriteLine(ex.StackTrace.ToString());
Console.WriteLine("---Registra o nome do método na qual a exceção ocorreu---");
Console.WriteLine(ex.TargetSite.ToString());
}
return "";
}
}
class Departamento
{
public String GetDepartmentos()
{
try
{
DividirPorZero();
return "Método GetDepartmentos foi chamado";
}
catch(Exception ex)
{
throw ex;
}
}
//estamos gerando uma exception
public void DividirPorZero()
{
throw new DivideByZeroException();
}
}
}
}
|
Neste código apenas alteramos o bloco try/catch e agora estamos lançando um throw ex.
Veja o resultado:
Analisando a pilha exibida na figura acima note que apenas os métodos GetDepartamentos e GetDetalhes foram gravados na pilha.
O método DividirPorZero() que foi a causa da exceção não foi gravado na pilha.
Como usamos throw ex no método GetDepartamentos a pilha removeu o DividirPorZero() da pilha.
Concluimos assim que throw mantém a hierarquia de exceções no rastreamento da pilha e fornece informações completas enquanto que throw ex retorna as exceções até o ponto no qual o código throw ex foi excecutado, ai, ele remove os detalhes da exceção ate este ponto.
Entendeu agora por que dar preferência a lançar apenas throw ?
(disse
Jesus) "Eu sou o
pão vivo que desceu do céu; se alguém comer deste pão, viverá para sempre; e o
pão que eu der é a minha carne, que eu darei pela vida do mundo. "
João 6:51
Referências: