Try / Catch / throw ou bien utilisation de int ? - C#/.NET managed - Programmation
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.
Marsh Posté le 11-04-2006 à 09:53:00
Exception, sinon, autant continuer à faire du vieux C ANSI
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.
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.
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 |
ou à la classe std::vector<T> du C++
T val = MyVector.at(index); // Balance une exception si tu depasses les bornes tandis que |
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
Marsh Posté le 27-04-2006 à 10:11:36
Trouvé dans mon RSS de news dotnet : http://www.codeproject.com/gen/des [...] orCode.asp
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.
Marsh Posté le 27-04-2006 à 16:53:29
bjone a écrit : haa Unreal et ses messages d'erreur |
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
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....
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...)
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.
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)
ou
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
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
Message édité par x1800+ le 10-04-2006 à 16:36:45