Préserver la pile Numéro de série original trace / ligne Exceptions .NET
-
22-09-2019 - |
Question
Comprendre la différence entre jeter ex et jeter , pourquoi le StackTrace d'origine conservé dans cet exemple:
static void Main(string[] args)
{
try
{
LongFaultyMethod();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
static void LongFaultyMethod()
{
try
{
int x = 20;
SomethingThatThrowsException(x);
}
catch (Exception)
{
throw;
}
}
static void SomethingThatThrowsException(int x)
{
int y = x / (x - x);
}
Mais pas dans celui-ci:
static void Main(string[] args)
{
try
{
LongFaultyMethod();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
static void LongFaultyMethod()
{
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception)
{
throw;
}
}
Le deuxième scénario est produit la même sortie que jeter ex serait?
Dans les deux cas, on attend de voir le numéro de ligne où y est initialisé.
La solution
Je ne suis pas sûr que cette limitation est dans le langage C #, la CLI, ou la mise en œuvre Microsoft de ces derniers, mais votre deuxième exemple est un cas où un appel explicite à Exception.InternalPreserveStackTrace
est nécessaire comme indiqué dans le poste suivant. Étant donné que cette méthode est internal
, il doit généralement être appelé par la réflexion. Les problèmes de performance impliqués dans ce qui peut être presque complètement allégées en créant un Action<Exception>
pour l'appel, comme indiqué à la fin de cette réponse.
Référence: exceptions et préserver Renvoi des la pile des appels trace complète
Modifier Après réexaminant ECMA-335 partition I §12.4.2 (gestion des exceptions) et la partition III §4.24 (rethrow), je crois maintenant que le comportement que vous voyez est une erreur sémantique le CLR (la mise en œuvre de Microsoft de la CLI). La seule référence spécifique au comportement est « A rethrow
ne modifie pas la trace de la pile dans l'objet. » Dans le cas décrit ici, le rethrow est en fait modifier la trace de la pile, ce qui rend le PreserveStackTrace
pirater une solution de contournement pour un défaut de savoir CLR.
static void LongFaultyMethod()
{
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception ex)
{
PreserveStackTrace(ex); // <-- add this line
throw;
}
}
PreserveStackTrace
est ici une optimisation de celui de cette entrée de blog:
private static readonly Action<Exception> _internalPreserveStackTrace =
(Action<Exception>)Delegate.CreateDelegate(
typeof(Action<Exception>),
typeof(Exception).GetMethod(
"InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic));
public static void PreserveStackTrace(Exception e)
{
_internalPreserveStackTrace(e);
}
Autres conseils
Parce que dans le second exemple, vous rethrowing exception de même méthode. Dans la première sa lancée de différents thats méthode pourquoi. Dans une portée de la méthode, trace pile peut être seulement une.
Faites comme suit, la meilleure façon est d'envelopper toujours une exception dans une nouvelle exception, de sorte que vous verrez la profondeur d'exception.
"Si rethrow a été publié dans le même méthode (exception trace de la pile ne possède une information de numéro de ligne par méthode, vous ne voyez jamais trace de la pile que dans le procédé A, à la ligne n ° 2 exception a été levée et en même Procédé A, il a été relancée à partir de la ligne numéro 17, il ne contiendra que la dernière numéro de ligne où exception relancée "
try
{
int x = 20;
int y = x / (x - 20);
}
catch (Exception ex)
{
// do something here.. like log or something
throw new Exception("Internal Exception", ex);
}
Je suis surpris par tant de commentaires pas lire mon commentaire !! J'ai écrit dans le commentaire que vous devriez probablement déboiser en toute sécurité , il y a diverses raisons, si le code de niveau supérieur mange exception et vous ne savez pas qui et où exception a été levée, l'exploitation forestière vous aide à couper exception !!
Si vous n'avez pas besoin de se connecter, alors ne pas attraper l'exception.