qual é a diferença entre
try { ... }
catch{ throw }
e
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Independentemente de o segundo mostrar uma mensagem?
qual é a diferença entre
try { ... }
catch{ throw }
e
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Independentemente de o segundo mostrar uma mensagem?
Respostas:
throw; repete a exceção original e preserva seu rastreamento de pilha original.
throw ex;lança a exceção original, mas redefine o rastreamento de pilha, destruindo todas as informações de rastreamento de pilha até o seu catchbloco.
throw ex;throw new Exception(ex.Message);é ainda pior. Ele cria uma Exceptioninstância totalmente nova , perdendo o rastreamento da pilha original da exceção, bem como seu tipo. (por exemplo IOException).
Além disso, algumas exceções contêm informações adicionais (por exemplo, ArgumentException.ParamName).
throw new Exception(ex.Message); também destruirá essas informações.
Em certos casos, convém agrupar todas as exceções em um objeto de exceção personalizado, para poder fornecer informações adicionais sobre o que o código estava fazendo quando a exceção foi lançada.
Para fazer isso, defina uma nova classe que herda Exception, adicione todos os quatro construtores de exceção e, opcionalmente, um construtor adicional que use InnerExceptioninformações adicionais e também jogue sua nova classe de exceção, passando excomo InnerExceptionparâmetro . Ao passar o original InnerException, você preserva todas as propriedades da exceção original, incluindo o rastreamento da pilha.
throw new MyCustomException(myMessage, ex);claro.
ex.Message, o que é pior.
[Serializable()].
throw;o número da linha real onde ocorreu a exceção é substituído pelo número da linha de throw;. Como você sugere lidar com isso? stackoverflow.com/questions/2493779/...
O primeiro preserva o rastreamento de pilha original:
try { ... }
catch
{
// Do something.
throw;
}
O segundo permite alterar o tipo da exceção e / ou a mensagem e outros dados:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
Há também uma terceira maneira pela qual você passa uma exceção interna:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
Eu recomendo usar:
Outro ponto que eu não vi ninguém fazer:
Se você não fizer nada no seu bloco de captura {}, tentar ... captura é inútil. Eu vejo isso o tempo todo:
try
{
//Code here
}
catch
{
throw;
}
Ou pior:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Pior ainda:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
throwlança novamente a exceção capturada, mantendo o rastreamento de pilha, enquanto throw new Exceptionperde alguns dos detalhes da exceção capturada.
Você normalmente usaria throwpor si só para registrar uma exceção sem manipulá-la totalmente nesse ponto.
O BlackWasp possui um bom artigo intitulado Throwing Exceptions in C # .
Lançar uma nova exceção afasta o rastreamento de pilha atual.
throw;manterá o rastreamento da pilha original e é quase sempre mais útil. A exceção a essa regra é quando você deseja agrupar a exceção em uma exceção personalizada de sua preferência. Você deve então fazer:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
throwé para relançar uma exceção capturada. Isso pode ser útil se você quiser fazer algo com a exceção antes de passar para a cadeia de chamadas.
O uso throwsem argumentos preserva a pilha de chamadas para fins de depuração.
Seu segundo exemplo redefinirá o rastreamento de pilha da exceção. O primeiro preserva com mais precisão as origens da exceção. Além disso, você desembrulhou o tipo original, essencial para saber o que realmente deu errado ... Se o segundo for necessário para a funcionalidade - por exemplo, para adicionar informações estendidas ou envolver novamente com um tipo especial, como uma 'HandleableException' personalizada, basta ser verifique se a propriedade InnerException também está definida!
A diferença mais importante é que a segunda expressão apaga o tipo de exceção. E o tipo de exceção desempenha um papel vital na captura de exceções:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
Se foo()jogar IOException, o [1]bloco catch irá capturar a exceção. Mas quando bar()jogado IOException, ele será convertido em Exceptionformiga comum e não será pego pelo [1]bloco catch.
throw ou throw ex, ambos são usados para lançar ou repetir a exceção, quando você simplesmente registra as informações de erro e não deseja enviar nenhuma informação ao chamador, simplesmente registra o erro em catch and leave. Mas, caso você queira enviar algumas informações significativas sobre a exceção para o chamador, use throw ou throw ex. Agora, a diferença entre throw e throw ex é que throw preserva o rastreamento de pilha e outras informações, mas throw ex cria um novo objeto de exceção e, portanto, o rastreamento de pilha original é perdido. Portanto, quando devemos usar throw and throw e, ainda existem algumas situações em que você pode querer relançar uma exceção como redefinir as informações da pilha de chamadas. Por exemplo, se o método estiver em uma biblioteca e você deseja ocultar os detalhes da biblioteca do código de chamada, você não necessariamente deseja que a pilha de chamadas inclua informações sobre métodos privados na biblioteca. Nesse caso, você pode capturar exceções nos métodos públicos da biblioteca e, em seguida, repeti-las novamente para que a pilha de chamadas comece nesses métodos públicos.
Nenhuma das respostas aqui mostra a diferença, o que pode ser útil para as pessoas que lutam para entender a diferença. Considere este código de exemplo:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
O que gera a seguinte saída:
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
O lance simples, conforme indicado nas respostas anteriores, mostra claramente a linha de código original que falhou (linha 12) e os dois outros pontos ativos na pilha de chamadas quando a exceção ocorreu (linhas 19 e 64).
A saída do caso re-throw mostra por que é um problema. Quando a exceção é repetida novamente, a exceção não inclui as informações da pilha original. Observe que apenas othrow e (linha 35) e o ponto da pilha de chamadas mais externas (linha 64) estão incluídos. Seria difícil rastrear o método fail () como a fonte do problema se você lançar exceções dessa maneira.
O último caso (innerThrow) é mais elaborado e inclui mais informações do que qualquer um dos itens acima. Como instanciamos uma nova exceção, temos a chance de adicionar informações contextuais (a mensagem "externa", aqui, mas também podemos adicionar ao dicionário .Data da nova exceção), além de preservar todas as informações no original exceção (incluindo links de ajuda, dicionário de dados etc.).