Je regarde l'article C # - Objet de transfert de données sur les DTO sérialisables.
L'article comprend ce morceau de code:
public static string SerializeDTO(DTO dto) {
try {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
catch(Exception ex) {
throw ex;
}
}
Le reste de l'article semble sain d'esprit et raisonnable (pour un noob), mais ce try-catch-throw lève une WtfException ... N'est-ce pas exactement équivalent à ne pas gérer les exceptions du tout?
Ergo:
public static string SerializeDTO(DTO dto) {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
Ou est-ce que je manque quelque chose de fondamental sur la gestion des erreurs en C #? C'est à peu près la même chose que Java (moins les exceptions vérifiées), n'est-ce pas? ... Autrement dit, ils ont tous deux affiné C ++.
La question du débordement de la pile La différence entre relancer la capture sans paramètre et ne rien faire? semble soutenir mon affirmation selon laquelle essayer-attraper-jeter est un non-op.
ÉDITER:
Juste pour résumer pour tous ceux qui trouveront ce fil à l'avenir ...
NE PAS
try {
// Do stuff that might throw an exception
}
catch (Exception e) {
throw e; // This destroys the strack trace information!
}
Les informations de trace de pile peuvent être cruciales pour identifier la cause première du problème!
FAIRE
try {
// Do stuff that might throw an exception
}
catch (SqlException e) {
// Log it
if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
// Do special cleanup, like maybe closing the "dirty" database connection.
throw; // This preserves the stack trace
}
}
catch (IOException e) {
// Log it
throw;
}
catch (Exception e) {
// Log it
throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
// Normal clean goes here (like closing open files).
}
Attrapez les exceptions les plus spécifiques avant les moins spécifiques (tout comme Java).
Références:
la source
Réponses:
Première; la façon dont le code de l'article le fait est mauvais.
throw ex
réinitialisera la pile d'appels dans l'exception au point où se trouve cette instruction throw; perdre les informations sur le lieu de création de l'exception.Deuxièmement, si vous attrapez et relancez simplement comme ça, je ne vois aucune valeur ajoutée, l'exemple de code ci-dessus serait tout aussi bon (ou, étant donné le
throw ex
bit, encore meilleur) sans le try-catch.Cependant, dans certains cas, vous souhaiterez peut-être intercepter et renvoyer une exception. La journalisation pourrait être l'une d'entre elles:
la source
ex
objet, alors il n'est pas nécessaire de l'instancier.throw ex
ne redémarre pas la trace de pile.Ne fais pas ça,
Vous perdrez les informations de trace de pile ...
Soit,
OU
Une des raisons pour lesquelles vous voudrez peut-être recommencer est si vous gérez différentes exceptions, par exemple
la source
C # (avant C # 6) ne prend pas en charge les "exceptions filtrées" CIL, ce que VB fait, donc en C # 1-5 une des raisons pour renvoyer une exception est que vous n'avez pas assez d'informations au moment de catch () pour déterminer si vous souhaitez réellement intercepter l'exception.
Par exemple, dans VB, vous pouvez faire
... qui ne gérerait pas MyExceptions avec différentes valeurs ErrorCode. En C # avant la v6, vous devrez intercepter et relancer MyException si le ErrorCode n'était pas 123:
Depuis C # 6.0, vous pouvez filtrer comme avec VB:
la source
Ma principale raison d'avoir du code comme:
est donc je peux avoir un point d'arrêt dans la capture, qui a un objet d'exception instancié. Je le fais beaucoup lors du développement / débogage. Bien sûr, le compilateur me donne un avertissement sur tous les e inutilisés, et idéalement, ils devraient être supprimés avant une version.
Ils sont sympas pendant le débogage.
la source
#if DEBUG
autour des DEUXtry {
et} catch () {...}
est un peu en désordre et, franchement, ça me rend mal à l'aise ... Le pré-processeur n'est, en général, pas mon ami.Une raison valable pour renvoyer des exceptions peut être que vous souhaitez ajouter des informations à l'exception, ou peut-être envelopper l'exception d'origine dans une de vos propres créations:
la source
Pas exactement, ce n'est pas pareil. Il réinitialise la trace de pile de l'exception. Bien que je convienne que c'est probablement une erreur, et donc un exemple de mauvais code.
la source
Vous ne voulez pas lancer d'ex - car cela perdra la pile d'appels. Voir Gestion des exceptions (MSDN).
Et oui, le try ... catch ne fait rien d'utile (à part perdre la pile d'appels - donc c'est en fait pire - à moins que pour une raison quelconque vous ne vouliez pas exposer cette information).
la source
Un point que les gens n'ont pas mentionné est que, bien que les langages .NET ne fassent pas vraiment de distinction, la question de savoir si l'on doit prendre des mesures lorsqu'une exception se produit et si l'on résoudra , sont en réalité des questions distinctes. Il y a de nombreux cas où l'on doit agir sur la base d'exceptions que l'on n'a aucun espoir de résoudre, et il y a des cas où tout ce qui est nécessaire pour "résoudre" une exception est de dérouler la pile jusqu'à un certain point - aucune autre action n'est requise .
En raison de la sagesse courante selon laquelle il ne faut «attraper» que des choses que l'on peut «gérer», beaucoup de code qui doit agir lorsque des exceptions se produisent, ne le fait pas. Par exemple, beaucoup de code va acquérir un verrou, mettre l'objet protégé "temporairement" dans un état qui viole ses invariants, puis le mettre dans un état légitime, puis relâcher le verrou avant que quiconque ne puisse voir l'objet. Si une exception se produit alors que l'objet est dans un état dangereusement invalide, la pratique courante consiste à libérer le verrou avec l'objet toujours dans cet état. Un modèle bien meilleur serait d'avoir une exception qui se produit alors que l'objet est dans une condition "dangereuse" invalide expressément le verrou de sorte que toute tentative future pour l'acquérir échouera immédiatement.
Dans la plupart des langages .NET, le seul moyen pour le code d'agir sur la base d'une exception est de le
catch
faire (même s'il sait que cela ne résoudra pas l'exception), d'exécuter l'action en question, puis de la refairethrow
). Une autre approche possible si le code ne se soucie pas de l'exception levée consiste à utiliser unok
indicateur avec untry/finally
bloc; définissez l'ok
indicateurfalse
avant le bloc ettrue
avant la fermeture du bloc, et avant tout élément sereturn
trouvant dans le bloc. Ensuite, à l'intérieurfinally
, supposez que s'ilok
n'est pas défini, une exception doit s'être produite. Une telle approche est sémantiquement meilleure que acatch
/throw
, mais elle est laide et est moins maintenable qu'elle ne devrait l'être.la source
Cela peut être utile lorsque votre programmation fonctionne pour une bibliothèque ou une DLL.
Cette structure de renvoi peut être utilisée pour réinitialiser délibérément la pile d'appels afin qu'au lieu de voir l'exception levée à partir d'une fonction individuelle à l'intérieur de la fonction, vous obteniez l'exception à partir de la fonction elle-même.
Je pense que c'est juste utilisé pour que les exceptions levées soient plus propres et n'entrent pas dans les "racines" de la bibliothèque.
la source
Une des raisons possibles pour intercepter est de désactiver le filtrage de tous les filtres d'exception plus en profondeur dans la pile ( ancien lien aléatoire ). Mais bien sûr, si telle était l'intention, il y aurait un commentaire à cet effet.
la source
Cela dépend de ce que vous faites dans le bloc catch et si vous souhaitez transmettre l'erreur au code appelant ou non.
Vous pourriez dire
Catch io.FileNotFoundExeption ex
et utiliser un autre chemin de fichier ou un autre, mais renvoyer l'erreur.Faire également
Throw
au lieu deThrow Ex
vous permet de conserver la trace complète de la pile. Throw ex redémarre la trace de la pile à partir de l'instruction throw (j'espère que cela a du sens).la source
Alors que la plupart des autres réponses fournissent de bons exemples de la raison pour laquelle vous pourriez vouloir rattraper une exception, personne ne semble avoir mentionné un scénario «enfin».
Un exemple de ceci est où vous avez une méthode dans laquelle vous placez le curseur (par exemple sur un curseur d'attente), la méthode a plusieurs points de sortie (par exemple if () return;) et vous voulez vous assurer que le curseur est réinitialisé à la fin de la méthode.
Pour ce faire, vous pouvez envelopper tout le code dans un try / catch / enfin. Dans la position finale, remettez le curseur sur le curseur droit. Afin de ne pas enterrer d'exceptions valides, jetez-le à nouveau dans la prise.
la source
catch
une partie obligatoiretry...finally
ou joue-t-il un rôle fonctionnel dans cet exemple? - Je viens de revérifier, et je peux utilisertry {} finally {}
sans le bloc catch du tout.Dans l'exemple du code que vous avez publié, il n'y a en fait aucun intérêt à intercepter l'exception car il n'y a rien de fait sur la capture qu'elle est juste repensée, en fait, cela fait plus de mal que de bien car la pile d'appels est perdue .
Cependant, vous intercepteriez une exception pour faire de la logique (par exemple, fermer la connexion sql du verrouillage de fichier, ou juste un peu de journalisation) en cas d'exception, la renvoyer au code appelant. Ce serait plus courant dans une couche métier que dans le code frontal car vous souhaiterez peut-être que le codeur implémentant votre couche métier gère l'exception.
Pour réitérer bien qu'il n'y ait aucun intérêt à intercepter l'exception dans l'exemple que vous avez publié. Ne le faites pas comme ça!
la source
Désolé, mais de nombreux exemples de "conception améliorée" sentent toujours horriblement ou peuvent être extrêmement trompeurs. Après avoir essayé {} catch {log; throw} est tout à fait inutile. La journalisation des exceptions doit être effectuée dans un emplacement central à l'intérieur de l'application. les exceptions bouillonnent de toute façon, pourquoi ne pas les enregistrer quelque part vers le haut et près des frontières du système?
Il faut être prudent lorsque vous sérialisez votre contexte (c'est-à-dire DTO dans un exemple donné) juste dans le message de journal. Il peut facilement contenir des informations sensibles dont on ne voudrait peut-être pas toucher toutes les personnes qui peuvent accéder aux fichiers journaux. Et si vous n'ajoutez aucune nouvelle information à l'exception, je ne vois vraiment pas l'intérêt de l'encapsulation d'exception. Le bon vieux Java a un certain point pour cela, il nécessite que l'appelant sache à quel type d'exceptions on doit s'attendre lors de l'appel du code. Étant donné que vous n'avez pas cela dans .NET, l'habillage ne fait aucun bien dans au moins 80% des cas que j'ai vus.
la source
En plus de ce que les autres ont dit, voir ma réponse à une question connexe qui montre que la capture et le retour ne sont pas un no-op (c'est en VB, mais une partie du code pourrait être appelé C # depuis VB).
la source
La plupart des réponses parlent de scénario catch-log-rethrow.
Au lieu de l'écrire dans votre code, envisagez d'utiliser AOP, en particulier Postsharp.Diagnostic.Toolkit avec OnExceptionOptions IncludeParameterValue et IncludeThisArgument
la source
Renvoyer les exceptions via
throw
est utile lorsque vous n'avez pas de code particulier pour gérer les exceptions actuelles, ou dans les cas où vous avez une logique pour gérer des cas d'erreur spécifiques mais que vous souhaitez ignorer tous les autres.Exemple:
Cependant, il existe également une autre façon de procéder, en utilisant des clauses conditionnelles dans les blocs catch:
la source