Try / Catch / throw ou bien utilisation de int ?

Try / Catch / throw ou bien utilisation de int ? - C#/.NET managed - Programmation

Marsh Posté le 10-04-2006 à 16:30:05    

Bien le bonjour,
 
Comme l'indique le titre, c'est une question que je me pose depuis quelques temps. :o  
 
Imaginons une fonction en C#, qui doit effectuer un banal traitement, mais en vérifiant qu'il n'y ai pas d'erreurs, et une autre qui appelle cette première fonction.
On a le choix entre deux solutions (peut-être plus, mais c'est les deux qui me viennent à l'esprit) [:canaille]  

Code :
  1. public void MaFonction()
  2. {
  3.     //Le code qui fait le traitement, avec un
  4.     //throw new MonException () en cas de probleme
  5. }
  6. public void MonAutreFonction()
  7. {
  8.     try
  9.     {   MaFonction();  }
  10.     catch (MonException ex)
  11.     {
  12.         // Un message d'erreur
  13.     }
  14. }


 
ou
 

Code :
  1. public int MaFonction()
  2. {
  3.      returnCode = -1;
  4.      // Le traitement, et au final on retourne 1 si pas de problème, ou 0 si il y a eu
  5.     // un probleme (detection par exemple via des tests conditionnels)
  6. }
  7. public void MonAutreFonction()
  8. {
  9.      int result = MaFonction();
  10.      // Suivant la valeur retournée, on agit de telle ou telle maniere
  11. }


 
La question que je me pose est : Quelle est la meilleure méthode?  
Certes les Exceptions et cie. sont pas faites pour les chiens, mais je me souvient avoir lu dans un article en anglais que utiliser des retours d'int à la place des throw etc. était une sorte d'optimisation  [:pingouino]
 
Je me demande donc si c'est vrai, laquelle de ces deux solutions est la plus fiable etc  :)  
Donc si quelqu'un pouvait éclairer ma lanterne, ça serait gentil  :D


Message édité par x1800+ le 10-04-2006 à 16:36:45
Reply

Marsh Posté le 10-04-2006 à 16:30:05   

Reply

Marsh Posté le 10-04-2006 à 17:27:37    

up :o

Reply

Marsh Posté le 10-04-2006 à 17:53:34    

les deux sont publiques. moi je dis exception

Reply

Marsh Posté le 10-04-2006 à 20:21:59    

Tu es obligé de traiter l'exception alors que tu peux oublier de traiter le code d'erreur. Si tu changes la définition des codes d'erreur, tu dois changer une bonne partie du code. En plus, rien ne t'empêche de traiter le  code d'erreur dans l'exception...
 
Bref, je vote exception aussi.

Reply

Marsh Posté le 11-04-2006 à 09:53:00    

Exception, sinon, autant continuer à faire du vieux C ANSI [:ddr555]

Reply

Marsh Posté le 11-04-2006 à 11:37:01    

Plusieurs remarques.
 
De tête, la norme ANSI (qui préconise l'utilisation d'un INT en retour) préconise :
0 = pas d'erreur
> 0 = erreur (avec la variable de retour = code d'erreur)
-1 = je ne sais pas s'il est traîté par ANSI, mais ça pourrait être "erreur inattendue"
 
ensuite, pour les code d'erreur qui change, il suffit de passer par un enum pour le code de retour, qui sera donc une liste de constantes avec un nom bien précis. ainsi, même si on change la valeur, aucun problème, puisque le nom ne changera pas (et rien ne nous empêche de faire une search & replace pour modifier les noms)
 
bref, la recommandation ANSI me semble guère moins maintenable que celle des exceptions.
 
ensuite, niveau mécanismes, l'utilisation des exceptions (surtout avec C#) va lancer des traîtements lourds dans le GC. c'est un point à prendre en considération. maintenant, même pour une appli PocketPC, je ne suis pas certain que la différence soit vraiment mesurable.
 
niveau sémantique, la norme ANSI a vu le jour alors que la notion d'exceptions était plus que rare, et généralement mal implémentée (nombre de compilateurs étaient incapable de reprendre un traîtement normal après la levée d'ue exception). maintenant, elles existent dans tous les langages évoluées, et selon moi ce n'est pas pour rien : come l'a dit slash33, tu ne peux pas ne pas contrôler une exception. deplus, lors du débug (ou de l'execution avec les symboles activés) cela permet plus de souplesse niveau débugage. je pense que c'est un point primordial.
 
ensuite, pour peut que ta fonction retourne une valeur, t'es un peu coincé avec un return de code d'erreur. tu dois toujours passer par des variables en byref, ce que personnellement, je déconseille très fortement, c'est rapidement très dangereux (genre on lance deux fois de suite le même traîtement sur une même variable à coup de copier/coller et on ne comprends pas pourquoi la seconde fois on n'a pas le même résultat. ça peut prendre des plombes à débuguer).
 
pour ma part, je combine parfois les deux.
 
je passe "byref" un objet "warnings", qui va contenir un code de warning en cas d'erreur non bloquante. et je throw une exception si j'ai une erreur réellement bloquante.
 
par exemple, un fichier qui va lire des valeurs dans un fichier de configuration :
-> Si j'arrive à lire le fichier et trouver la valeur, je vais mettre "normal" dans mon objet warning, et retourner la valeur sans problème.
-> Si j'arrive à lire le fichier, mais que je ne trouve pas la valeur, je vais mettre "valNotFound" dans warning, et retourner la valeur par défaut.
-> Si je ne trouve pas le fichier, je mets "iniFileNotFound" dans warning, et je retourne la valeur par défaut.
-> Si j'obtiens une erreur IOException à la lecture du fichier, ou que la valeur est incorrecte, je fout "fatalError" dans warning, et je throw une exception "unhandledException" avec comme source l'erreur système obtenur.
 
Ainsi, dans les parties du code où je me fout de savoir si je fichier de paramètres est correct, je me contente de lire le fichier en vérifiant s'il n'y a pas d'exception. et pour les parties où j'exige que le fichier soit correct (genre vérification qu'on a bien écrit une valeur), je check le warning en plus de l'exception, afin de fournir à l'utilisateur des informations relatives à l'erreur non bloquante rencontrée.

Reply

Marsh Posté le 11-04-2006 à 13:20:38    

Arjuna a écrit :

comme l'a dit slash33, tu ne peux pas ne pas contrôler une exception.


Ce n'est pas exactement ça. En C++, il est tout à fait possible de ne pas capturer l'exception qui se propagera jusqu'au plus haut niveau (en MFC elle est même capturée par un traitement par défaut). Par contre, tu est garanti  de l'interruption du code en cours pour remonter jusqu'au niveau de la capture de l'exception. D'autres langages sont encore moins permissifs, je pense par exemple à Java.
 
Pour le reste, entièrement d'accord. Ton exemple montre bien aussi l'enjeu de telle ou telle solution. Il s'agit simplement de bien définir sa stratégie de gestion des erreurs au moment de la conception, de l'adapter et de la justifier. Un classique : comment gérer la linguisitique dans les messages d'erreur ? Les MFC s'appuient sur les ressources de l'application, en Java j'utilisais le système de properties et disposais ainsi de ressources externalisées. Il y a encore beaucoup d'autres manières de procéder.


Message édité par slash33 le 11-04-2006 à 13:27:44
Reply

Marsh Posté le 24-04-2006 à 02:05:34    

Comme dit précédemment, tu peux mixer les deux approches : réfère toi à la classe System.Collections.Generic.Dictionary<K,V>

V val = MyDictionary[key];                       // Est plus lourd que
bool found = MyDictionary.TryGetValue(key, val); // dans le cas ou key n'existe pas.


ou à la classe std::vector<T> du C++

T val = MyVector.at(index); // Balance une exception si tu depasses les bornes tandis que
val = MyVector[index];      // te crache un segfault ou au mieux une valeur bidon (c'est pas standard mais c'est comme ca dans la pratique si je ne m'abuse.)


Retourner un int dans le cadre d'un programme C# (lire .NET managed) peut eventuellement être une optimisation. Maintenant, demande toi si tu nécessites vraiment cette optimisation compte tenu des contraintes qu'elle t'impose.
 
Maintenir la lisibilité de ses source plutôt que leur vitesse d'execution reste souvent la meilleure approche. Tu es le seul juge.
 
EDIT:

Citation :

Un classique : comment gérer la linguisitique dans les messages d'erreur ? Les MFC s'appuient sur les ressources de l'application, en Java j'utilisais le système de properties et disposais ainsi de ressources externalisées. Il y a encore beaucoup d'autres manières de procéder.

Il est générallement déconseiller de confondre la gestion d'erreur de son affichage a l'utilisateur qui s'en balance des stack traces et autres joyeusetés du genre
 
http://node.to/fun/unreal_error.gif


Message édité par cnstrnd le 24-04-2006 à 02:29:59
Reply

Marsh Posté le 27-04-2006 à 10:11:36    

Trouvé dans mon RSS de news dotnet : http://www.codeproject.com/gen/des [...] orCode.asp

Reply

Marsh Posté le 27-04-2006 à 10:37:09    

En fait, ce qu'il faut bien déterminer ce sont les conditions d'erreur: si une exception est peu ou prou gratuite à mettre en place (try/catch) elle comporte un coût non négligeable à l'utilisation. Elle est donc à réserver principalement aux situations anormales, rares, au traitement bizarre (e.g. bubbling) et aux erreurs mettant en jeu l'intégrité même du logiciel.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 27-04-2006 à 10:37:09   

Reply

Marsh Posté le 27-04-2006 à 11:21:28    

haa Unreal et ses messages d'erreur :D

Reply

Marsh Posté le 27-04-2006 à 16:53:29    

bjone a écrit :

haa Unreal et ses messages d'erreur :D


en lisant ça je me dis que... euh... ils ont compilé ce jeu en mode débug ??? ils ont laissé les symboles dedans ??? c'est vraiment des charlots :o

Reply

Marsh Posté le 27-04-2006 à 17:22:47    

nan je sais pas trop comment ils implémenté leur truc, j'y ai jamais réfléchi plus que ça.
 
tu moment que ça impactes pas les perfs....

Reply

Marsh Posté le 29-04-2006 à 11:44:58    

Ca doit être une pile d'appels mais elle clairement illisible en l'état.
 
Pour mes messages d'erreurs je parlais bien évidemment de quelque chose compréhensible par l'utilisateur (m'enfin si l'utilisateur est un programmeur...)


Message édité par slash33 le 29-04-2006 à 11:46:07
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed