Comment lever une exception sans réinitialiser la trace de stack?

Cette question fait suite à Y at-il une différence entre «lancer» et «lancer ex» ?

Existe-t-il un moyen d’extraire une nouvelle méthode de traitement des erreurs sans réinitialiser la trace de stack?

[EDIT] Je vais essayer à la fois la “méthode interne” et une autre réponse fournie par Earwicker et voir quelle méthode convient le mieux pour marquer une réponse.

Je ne sais pas si vous voulez dire cela, mais ma suggestion dans votre autre question visait à résoudre ce problème.

Si votre gestionnaire renvoie un booléen, que l’exception ait été gérée ou non, vous pouvez l’utiliser dans votre clause catch:

catch (Exception ex) { if (!HandleException(ex)) { throw; } } 

Oui; C’est à cela que sert la propriété InnerException.

 catch(Exception ex) { throw new YourExceptionClass("message", ex); } 

Cela vous permettra d’append votre propre logique, puis de lancer votre propre classe d’exception. La stack StackTrace de l’instance YourExceptionClass proviendra de ce bloc de code, mais l’innerException sera l’exception que vous avez interceptée, avec la stack Stack qu’elle avait auparavant.

Avec .NET Framework 4.5, il existe maintenant un ExceptionDispatchInfo qui prend en charge ce scénario exact. Il permet de capturer une exception complète et de la renvoyer depuis un autre emplacement sans écraser la trace de stack contenue.

échantillon de code en raison d’une demande dans un commentaire

 using System.Runtime.ExceptionServices; class Test { private ExceptionDispatchInfo _exInfo; public void DeleteNoThrow(ssortingng path) { try { File.Delete(path); } catch(IOException ex) { // Capture exception (including stack trace) for later rethrow. _exInfo = ExceptionDispatchInfo.Capture(ex); } } public Exception GetFailure() { // You can access the captured exception without rethrowing. return _exInfo != null ? _exInfo.SourceException : null; } public void ThrowIfFailed() { // This will rethrow the exception including the stack trace of the // original DeleteNoThrow call. _exInfo.Throw(); // Contrast with 'throw GetFailure()' which rethrows the exception but // overwrites the stack trace to the current caller of ThrowIfFailed. } } 

Vous ne voulez pas créer une nouvelle exception avec la trace de stack d’origine. C’est trompeur, car cette trace de stack n’a pas créé la nouvelle exception.

Vous pouvez toutefois placer l’exception d’origine dans votre nouvelle exception en tant qu’exception “InnerException”. Est-ce que cela ferait ce que vous cherchez?

Attrapez-vous les exceptions que vous souhaitez filtrer plus attentivement afin de pouvoir changer d’avis, décider de ne pas les gérer et de les relancer?

Si vous voulez être vraiment prudent à ce sujet, ce n’est pas vraiment une bonne idée. Il vaut mieux ne jamais attraper l’exception en premier lieu. La raison est qu’un gestionnaire try/catch donné ne devrait pas prendre la décision d’exécuter des blocs nesteds finally pour des exceptions qu’il ne s’attend pas à voir. Par exemple, s’il existe une NullReferenceException , c’est probablement une très mauvaise idée de continuer à exécuter du code car cela provoquerait probablement la levée d’une autre exception de ce type. Et finally blocs ne sont que du code, comme tout autre code. Dès qu’une exception est interceptée pour la première fois, tous les blocs finaux de la stack situés sous try/catch sont exécutés. Il est alors trop tard. Une autre exception peut être générée, ce qui signifie que l’exception d’origine est perdue.

Cela implique (en C #) que vous devez soigneusement écrire un gestionnaire de catch distinct pour tous les types d’exceptions que vous souhaitez capturer. Cela implique également que vous ne pouvez filtrer que par type d’exception. C’est parfois un conseil très difficile à suivre.

Il devrait être possible de filtrer les exceptions d’une autre manière, mais pas en C #. Cependant, cela est possible dans VB.NET, et la BCL elle-même en tire parti en écrivant une petite quantité de code dans VB.NET afin de filtrer les exceptions de manière plus pratique.

Voici une explication détaillée, avec un exemple de code VB.NET, tirée du blog de l’équipe CLR.

Et voici mes deux cents.