Quelles sont les meilleures pratiques à prendre en compte lors de la capture d'exceptions et de leur réexécution? Je veux m'assurer que l' Exception
objet InnerException
et la trace de pile sont préservés. Y a-t-il une différence entre les blocs de code suivants dans la façon dont ils gèrent cela?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Contre:
try
{
//some code
}
catch
{
throw;
}
la source
ExceptionDispatchInfo.Capture(ex).Throw(); throw;
dans .NET +4.5 stackoverflow.com/questions/57383/…Si vous lancez une nouvelle exception avec l'exception initiale, vous préserverez également la trace de pile initiale.
la source
AggregateException
ne doit être utilisé que pour des exceptions sur des opérations agrégées. Par exemple, il est lancé par les classesParallelEnumerable
etTask
du CLR. L'utilisation devrait probablement suivre cet exemple.En fait, il existe certaines situations dans lesquelles la
throw
déclaration ne conservera pas les informations StackTrace. Par exemple, dans le code ci-dessous:Le StackTrace indiquera que la ligne 54 a soulevé l'exception, bien qu'elle ait été soulevée à la ligne 47.
Dans des situations comme celle décrite ci-dessus, il existe deux options pour préconfigurer le StackTrace d'origine:
Appel de l'exception.InternalPreserveStackTrace
Comme il s'agit d'une méthode privée, elle doit être invoquée en utilisant la réflexion:
J'ai un inconvénient à compter sur une méthode privée pour conserver les informations StackTrace. Il pourra être modifié dans les futures versions de .NET Framework. L'exemple de code ci-dessus et la solution proposée ci-dessous ont été extraits du blog Fabrice MARGUERIE .
Appel d'Exception.SetObjectData
La technique ci-dessous a été suggérée par Anton Tykhyy comme réponse à In C #, comment puis-je relancer InnerException sans perdre la question de trace de pile .
Bien qu'il ait l'avantage de s'appuyer uniquement sur des méthodes publiques, il dépend également du constructeur d'exceptions suivant (que certaines exceptions développées par des tiers ne mettent pas en œuvre):
Dans ma situation, j'ai dû choisir la première approche, car les exceptions soulevées par une bibliothèque tierce que j'utilisais n'ont pas implémenté ce constructeur.
la source
Lorsque vous
throw ex
, vous jetez essentiellement une nouvelle exception et vous manquerez les informations de trace de pile d'origine.throw
est la méthode préférée.la source
La règle d'or est d'éviter d'attraper et de lancer l'
Exception
objet de base . Cela vous oblige à être un peu plus intelligent sur les exceptions; en d'autres termes, vous devriez avoir un catch explicite pour aSqlException
afin que votre code de manipulation ne fasse pas quelque chose de mal avec aNullReferenceException
.Dans le monde réel, cependant, attraper et enregistrer l'exception de base est également une bonne pratique, mais n'oubliez pas de parcourir le tout pour en obtenir
InnerExceptions
.la source
Vous devez toujours utiliser "throw;" pour renvoyer les exceptions dans .NET,
Reportez-vous à ceci, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Fondamentalement, MSIL (CIL) a deux instructions - "lancer" et "relancer":
Fondamentalement, je peux voir la raison pour laquelle "throw ex" remplace la trace de la pile.
la source
throw ex;
retourner: en Java, c'est le cas! Mais vous devez inclure cette information ici pour avoir une réponse de catégorie A. (Bien que je rattrape toujours laExceptionDispatchInfo.Capture
réponse de jeuoekdcwzfwccu .)Personne n'a expliqué la différence entre
ExceptionDispatchInfo.Capture( ex ).Throw()
et une plainethrow
, alors la voici. Cependant, certaines personnes ont remarqué le problème avecthrow
.La manière complète de renvoyer une exception interceptée consiste à utiliser
ExceptionDispatchInfo.Capture( ex ).Throw()
(uniquement disponible à partir de .Net 4.5).Vous trouverez ci-dessous les cas nécessaires pour tester cela:
1.
2.
3.
4.
Le cas 1 et le cas 2 vous donneront une trace de pile où le numéro de ligne de code source pour la
CallingMethod
méthode est le numéro dethrow new Exception( "TEST" )
ligne de la ligne.Cependant, le cas 3 vous donnera une trace de pile où le numéro de ligne de code source pour la
CallingMethod
méthode est le numéro de ligne de l'throw
appel. Cela signifie que si lathrow new Exception( "TEST" )
ligne est entourée d'autres opérations, vous ne savez pas à quel numéro de ligne l'exception a été levée.Le cas 4 est similaire au cas 2 parce que le numéro de ligne de l'exception d'origine est conservé, mais n'est pas un véritable renversement car il change le type de l'exception d'origine.
la source
throw ex;
et c'est la meilleure réponse de tous.Quelques personnes ont en fait raté un point très important - «jeter» et «jeter ex» peut faire la même chose mais ils ne vous donnent pas une information cruciale qui est la ligne où l'exception s'est produite.
Considérez le code suivant:
Lorsque vous effectuez un `` lancer '' ou un `` lancer ex '', vous obtenez la trace de la pile, mais la ligne # va être # 22, vous ne pouvez donc pas savoir quelle ligne exactement lançait l'exception (sauf si vous n'en avez que 1 ou quelques lignes de code dans le bloc try). Pour obtenir la ligne n ° 17 attendue dans votre exception, vous devrez lancer une nouvelle exception avec la trace de pile d'exceptions d'origine.
la source
Vous pouvez également utiliser:
Et toutes les exceptions levées vont remonter au niveau suivant qui les gère.
la source
J'utiliserais certainement:
Cela préservera votre pile.
la source
throw
; par exemple, vous pouvez nettoyer un jetable (où vous l'appelez UNIQUEMENT en cas d'erreur), puis lever l'exception.Pour info je viens de tester ceci et la trace de pile rapportée par 'throw;' n'est pas une trace de pile entièrement correcte. Exemple:
La trace de pile pointe correctement vers l'origine de l'exception (numéro de ligne signalé) mais le numéro de ligne signalé pour foo () est la ligne du lancer; , par conséquent, vous ne pouvez pas dire lequel des appels à bar () a provoqué l'exception.
la source