7
votes

Bonnes pratiques lors de la manipulation des exceptions en C #

J'ai lu dans le programmeur pragmatique et dans d'autres articles (dont un de Joel Spolsky), que vous devriez seulement lancer des exceptions dans des cas exceptionnels exceptionnels. Sinon, vous devriez retourner une erreur.

Parfois, il est possible (retourner -1 , -0 ou a nombre positif , par exemple), mais il y a d'autres cas où cela n'est pas possible. Je veux dire, si vous retournez une classe, vous pouvez toujours retourner null , mais je pense que l'idée est de retourner quelque chose qui alerte l'appelant ce qui s'est passé.

Si je retourne toujours null , je ne pense pas qu'il soit utile de dire: Si cette méthode renvoie NULL, cela pourrait être à cause de A, B, C, D, ou E

alors, comment peut-on mettre en œuvre exactement en C #?

edit:
Heures après avoir posté cette question, j'ai vu une autre question ici où la question elle-même était de savoir siéter le code posté dans une bonne pratique ou non.

Je vois que c'est une autre façon de faire ce que je demandais ici. Voici le lien:

inconvénients de la propriété générique?


9 commentaires

Le problème est que le voeu de penser supposait que chaque consommateur fera le code de retour en code de retour qu'ils sont censés. Et cela signifie qu'ils ne détecteront pas lorsque votre méthode a échoué. Des exceptions font de l'API beaucoup plus facile à utiliser. Toujours les jeter quand une méthode n'a pas réussi à terminer la tâche qu'elle a été appelée à faire. Le point est jamais pour les utiliser pour le contrôle de flux.


@Codygray c'est comme ça que je fais cela, et je suis totalement d'accord avec vous, mais je ne pouvais pas résister à vous demander quand je lisais la même chose sur deux (et bons) endroits différents au même jour: le programmateur pragmatique et Joel sur Blog de logiciel.


Assez juste. J'aurais affiché une réponse plus complète, mais il y a déjà un accepté et on dirait que les meilleures réponses votées couvrent assez bien. Les exceptions sont un sujet très mal compris et vous verrez beaucoup de programmeurs familiarisés avec la manière dont ils travaillent en C ++ qui découragent à tort leur utilisation en C #. .NET Framework Design Guidelines est une excellente ressource .


@Codygray Toute autre référence pour continuer à lire sur Exceptions sont un sujet très mal compris ?


Difficile de filtrer la désinformation des suggestions valides. Cela rend les ressources en ligne très délicates. Les FDG sont la meilleure référence que je connaisse. Vous trouverez également de nombreux programmeurs qui appliquent leurs connaissances d'exceptions C ++ à C # ou à parler de manière pragmatique, disent que quelque chose n'est nécessaire que parce qu'ils ignorent des alternatives. Je discute souvent que les exceptions attrapantes et reprochèrent simplement pour les loger sont presque toujours la mauvaise idée. Cela offense aux gens qui pensent que je n'ai aucune "expérience du monde réel". Quelque chose comme le appdomain.unhandleXception est toujours un meilleur appel.


J'ai écrit plusieurs réponses sur les meilleures pratiques de traitement des exceptions. Celui-ci vient immédiatement à l'esprit. Et Celui-ci Il y a quelques instants. Il y en a probablement d'autres aussi. Et puis la partie très délicate comprend les limitations des piles d'appel Windows. Les textes de Russinovich sont impératifs pour cela.


Eric Lippert a un bon article sur ce site disponible en ligne. Lisez-le ici . La chose à faire attention à il y a ce qu'il appelle "exceptions vexaces". Ce sont ceux la plupart des gens parlent quand ils vous disent de ne pas lancer d'exceptions. Sinon, échouer rapidement concerne la meilleure stratégie autour. Vous souhaitez réparer tout ce qui cause l'exception lors du débogage ou de ne rien faire de rien et laissez le programme échouer. Si l'état a été corrompu et que vous ne pouvez pas le réparer, vous ferez mieux de vous écraser.


@Codygray génial! Je vais jeter un coup d'œil à eux :) Vous devriez fusionner ces 5 commentaires et les placer dans une réponse;) Merci.


Lancer des exceptions est également agréable que vous puissiez fournir des messages d'erreur comme des cordes plutôt que de renvoyer des codes d'erreur que vous devez rechercher le sens de.


7 Réponses :


10
votes

En utilisant des chiffres, vous contraignez directement ce que recommandez Microsoft avec des exceptions. La meilleure source d'informations que j'ai constatées que désordonnez tout le sujet, est CLR de Jeffrey Richter via C # 3 . Aussi le .NET Frameworks livre vaut une lecture pour son matériau sur des exceptions.

pour citer MSDN :

ne renvoie pas les codes d'erreur. Les exceptions sont le principal moyen de signaler des erreurs dans des cadres.

une solution que vous pouvez adopter est un paramètre out> out>, qui obtient le résultat. Votre méthode renvoie ensuite un bool beaucoup comme beaucoup tryparse méthodes que vous rencontrez dans le cadre.


0 commentaires

8
votes

Un exemple à considérer est int.tryparse . Qui utilise un paramètre out> sur la valeur analysée et une valeur de retour bool pour indiquer le succès ou l'échec. Le bool pourrait être remplacé par un objet enum ou un objet plus complexe si la situation le mérite. (Par exemple, la validation des données pourrait échouer d'une manière qui justifierait vraiment une collection d'échecs, etc.)

une alternative à celle-ci avec .NET 4 est tuple ... donc int. Int. Tryparse pourrait être avoir été: xxx

La possibilité suivante est d'avoir un objet encapsulant tout le résultat, y compris le mode de défaillance, le cas échéant. . Par exemple, vous pouvez demander à une tâche pour son résultat, son statut et son exception s'il est échoué.

Tout cela n'est approprié que si ce n'est pas vraiment un l'erreur pour que cela se produise, comme tel. Cela n'indique pas un bogue, juste quelque chose comme une mauvaise entrée utilisateur. Je n'ai vraiment pas comme les codes d'erreur de retour - les exceptions sont beaucoup plus idiomatiques dans .NET.


10 commentaires

ACK ... Je ne pense pas que je voudrais passer beaucoup de temps à travailler avec une API publique saupoudrée de tuples.


@Jack - Ce genre d'API fonctionnerait bien si la langue a soutenu l'expansion de tuple (ex: f #) .


@Chaospandion: Oui, cela fonctionnerait certainement mieux avec le soutien de la langue. À quel point je pense que cela serait infiniment préférable au paramètre , personnellement.


Comment savoir ce que représentent l'int-et-bool dans l'exemple ci-dessus? Un peu évident dans cette situation je suppose, mais tout ce qui est plus complexe pourrait être méchant. Je ne suis pas un fan de la partie Param Out.


@Jack: Comment savez-vous ce qu'elles représentent quand on est une valeur de retour et que l'un est un paramètre OUT? Il est vrai que l'utilisation de tuple est une jolie méthode ad hoc de combiner plusieurs valeurs de retour, mais je crois en la pratique, il serait assez clair, surtout si le support linguistique vous permettra d'écrire var (valeur, ok) = int.parse (texte); pour déclarer deux variables, valeur (un int ) et ok (A < code> bool ).


Pas un fan de l'une ou l'autre option, personnellement. Je préférerais avoir un objet bien défini renvoyé si j'ai besoin de quelque chose de plus que dire un Bool ou un Int. Préférence personnelle. :)


C'est quelque chose que j'aime vraiment de Python: /


@Jack: Je pense que pour le simple succès / échec + Résultat, un tuple irait bien. Pour quelque chose de plus complexe, un type séparé est approprié.


Pourquoi ne pas avoir tryparse renvoyer simplement un int? ?


@Thomsmith: Oui, c'est une autre option - cela ne fonctionne pas pour des situations similaires où null serait un résultat valide cependant.



1
votes

Microsoft a documenté les meilleures pratiques pour la manipulation des erreurs dans .NET

http://msdn.microsoft.com/fr -US / Bibliothèque / 8ey5ey87 (vs.71) .aspx

Je recommande de suivre ces lignes directrices, car c'est la norme pour .NET et vous aurez beaucoup moins de conflits avec d'autres développeurs .NET.

(note, je me rends compte que j'ai affiché à un lien plus ancien, mais les recommandations sont restées.)

Je me rends également compte que différentes plates-formes varient de la manière dont ils affichent une bonne gestion des erreurs. Cela pourrait être une question subjective, mais je vais coller à ce que j'ai dit ci-dessus - lorsque vous développez dans .net Suivez les directives .NET.


0 commentaires

1
votes

Vous voudrez peut-être envisager de suivre le modèle tryxxx code> avec un couple de surcharges simples pour le client à considérer.

// Exception
public void Connect(Options o); 

// Error Code
public bool TryConnect(Options o, out Error e); 


0 commentaires

0
votes

Je renvoie de telles valeurs comme null des références ou des valeurs d'index négatives uniquement si je suis sûr qu'il n'y aura pas de malentendu lorsque le code sera utilisé par un autre développeur. Quelque chose comme Linq fonction ienumerable .firstambefault . iEnumerable .First jette une exception pour les collections vides, car elle devrait renvoyer le premier élément, et la collection vide est un cas exceptionnel


0 commentaires

12
votes

une règle beaucoup meilleure pour quand jeter des exceptions est la suivante:

lancer une exception lorsque votre méthode ne peut pas faire ce que son nom dit qu'il le fait.

Une valeur null peut être utilisée pour indiquer que vous avez demandé quelque chose qui n'existe pas. Il ne doit pas être retourné pour une autre condition d'erreur.

La règle "seules seules des exceptions dans des cas exceptionnelles" est inutile de gaufres IMO car elle ne vous donne aucun point de référence pour indiquer ce qui est exceptionnel et ce qui n'est pas. C'est comme dire "seulement manger des aliments qui sont comestibles."


2 commentaires

J'aime vraiment cette réponse car elle fournit une description la moins ambiguë par une marge tout à fait une marge.


À cela, j'ajouterais que si la méthode appelée tryxxx ne peut pas faire xxx pour une raison que l'appelant anticipant probablement, il a essayé de faire xxx (ce qui signifie qu'il a dit son nom, et ne devrait donc pas jeter une exception); Si l'échec est un appel, un appelant n'est probablement pas préparé pour, il peut être bon de jeter une exception, en tenant compte que quelque chose l'empêchait de donner xxx un "bon essais".



1
votes

Joel Spolsky est faux. Statut de retour via des codes d'erreur / de retour signifie que vous ne pouvez pas faire confiance aux résultats d'une invocation de méthode - la valeur renvoyée doit être testée et traitée.

Cela signifie que chaque invocation de méthode renvoyant une telle valeur introduit au moins un point de choix. (ou plus, selon le domaine de la valeur renvoyée), et donc plus de chemins d'exécution possibles à travers le code. Toutes lesquelles doivent être testées. P>

Ce code, supposant ainsi que le contrat de méthode1 () et de méthode2 () est de réussir ou de lancer une exception, a peut-être un flux éventuellement. P>

bool fooSuccess = foo.Method(...);
if ( fooSuccess )
{
  bool barSuccess = bar.Method(...);
  if ( barSuccess )
  {
    // The normal course of events -- do the usual thing
  }
  else
  {
    // deal with bar.Method() failure
  }
}
else // foo.Method() failed
{
  // deal with foo.Method() failure
}


0 commentaires