Quais são as melhores práticas a serem consideradas ao capturar exceções e lançá-las novamente? Quero garantir que o rastreamento do Exception
objeto InnerException
e da pilha sejam preservados. Existe uma diferença entre os seguintes blocos de código na maneira como eles lidam com isso?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
fonte
ExceptionDispatchInfo.Capture(ex).Throw(); throw;
no .NET +4.5 stackoverflow.com/questions/57383/…Se você lançar uma nova exceção com a exceção inicial, preservará também o rastreio inicial da pilha.
fonte
AggregateException
deve ser usado apenas para exceções sobre operações agregadas. Por exemplo, ele é lançado pelas classesParallelEnumerable
eTask
do CLR. O uso provavelmente deve seguir este exemplo.Na verdade, existem algumas situações em que a
throw
declaração não preserva as informações do StackTrace. Por exemplo, no código abaixo:O StackTrace indicará que a linha 54 gerou a exceção, embora tenha sido gerada na linha 47.
Em situações como a descrita acima, existem duas opções para preservar o StackTrace original:
Chamando o Exception.InternalPreserveStackTrace
Como é um método privado, ele deve ser chamado usando reflexão:
Eu tenho uma desvantagem de depender de um método privado para preservar as informações do StackTrace. Pode ser alterado em versões futuras do .NET Framework. O exemplo de código acima e a solução proposta abaixo foram extraídos do blog Fabrice MARGUERIE .
Chamando Exception.SetObjectData
A técnica abaixo foi sugerida por Anton Tykhyy como resposta ao In C #, como posso reconfigurar o InnerException sem perder a pergunta de rastreamento de pilha .
Embora tenha a vantagem de confiar apenas em métodos públicos, também depende do construtor de exceções a seguir (que algumas exceções desenvolvidas por terceiros não implementam):
Na minha situação, tive que escolher a primeira abordagem, porque as exceções levantadas por uma biblioteca de terceiros que eu estava usando não implementaram esse construtor.
fonte
Quando você
throw ex
, basicamente, lança uma nova exceção e perde as informações originais de rastreamento da pilha.throw
é o método preferido.fonte
A regra geral é evitar pegar e jogar o
Exception
objeto básico . Isso força você a ser um pouco mais inteligente em relação às exceções; em outras palavras, você deve ter uma captura explícita para aSqlException
para que seu código de manipulação não faça algo errado com aNullReferenceException
.No mundo real, porém, capturar e registrar a exceção básica também é uma boa prática, mas não esqueça de acompanhar a coisa toda para obter a que
InnerExceptions
ela possa ter.fonte
Você sempre deve usar "throw"; para rever novamente as exceções no .NET,
Consulte isso, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Basicamente, o MSIL (CIL) tem duas instruções - "throw" e "rehrow":
Basicamente, posso ver o motivo pelo qual "throw ex" substitui o rastreamento da pilha.
fonte
throw ex;
vai relançar - em Java, é verdade! Mas você deve incluir essas informações aqui para obter uma resposta de grau A. (Embora eu ainda esteja alcançando aExceptionDispatchInfo.Capture
resposta de jeuoekdcwzfwccu .)Ninguém explicou a diferença entre
ExceptionDispatchInfo.Capture( ex ).Throw()
e uma planíciethrow
, então aqui está. No entanto, algumas pessoas notaram o problemathrow
.A maneira completa de reconfigurar uma exceção capturada é usar
ExceptionDispatchInfo.Capture( ex ).Throw()
(disponível apenas no .Net 4.5).Abaixo há os casos necessários para testar isso:
1
2)
3)
4)
O caso 1 e o caso 2 fornecerão um rastreamento de pilha em que o número da linha do código-fonte do
CallingMethod
método é o número dathrow new Exception( "TEST" )
linha.No entanto, o caso 3 fornecerá um rastreamento de pilha em que o número da linha do código-fonte do
CallingMethod
método é o número da linha dathrow
chamada. Isso significa que, se athrow new Exception( "TEST" )
linha estiver cercada por outras operações, você não terá idéia de qual número de linha a exceção foi realmente lançada.O caso 4 é semelhante ao caso 2, porque o número da linha da exceção original é preservado, mas não é uma releitura real, pois altera o tipo da exceção original.
fonte
throw ex;
e esta é a melhor resposta de todas.Algumas pessoas realmente perderam um ponto muito importante - 'throw' e 'throw ex' podem fazer a mesma coisa, mas não fornecem uma peça de informação crucial, que é a linha em que a exceção aconteceu.
Considere o seguinte código:
Quando você faz um 'throw' ou 'throw ex', obtém o rastreamento da pilha, mas a linha # será # 22; portanto, não é possível descobrir qual linha estava lançando exatamente a exceção (a menos que você tenha apenas 1 ou poucos linhas de código no bloco try). Para obter a linha 17 esperada em sua exceção, você precisará lançar uma nova exceção com o rastreamento da pilha de exceções original.
fonte
Você também pode usar:
E quaisquer exceções lançadas subirão para o próximo nível que as trata.
fonte
Eu definitivamente usaria:
Isso preservará sua pilha.
fonte
throw
; por exemplo, você pode limpar um descartável (onde você chama apenas de erro) e depois lançar a exceção.Para sua informação, acabei de testar isso e o rastreamento de pilha relatado por 'throw;' não é um rastreamento de pilha totalmente correto. Exemplo:
O rastreamento da pilha aponta para a origem da exceção corretamente (número da linha relatada), mas o número da linha relatada para foo () é a linha do lançamento; , portanto, você não pode dizer qual das chamadas para bar () causou a exceção.
fonte