Question

J'ai vu des gens dire qu'il est mauvais d'utiliser une capture sans arguments, surtout si cette capture ne fait rien:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

Cependant, cela est considéré comme une bonne forme:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

Autant que je sache, la seule différence entre le code de nettoyage dans un bloc finally et le code de nettoyage après les blocs try..catch est que vous avez des instructions de retour dans votre bloc try (dans ce cas, le code de nettoyage dans enfin sera exécuté, mais le code après le try..catch ne sera pas).

Sinon, qu'est-ce qui a de si spécial enfin?

Était-ce utile?

La solution

La grande différence est que try ... catch avalera l'exception, masquant ainsi le fait qu'une erreur s'est produite. try..finally exécutera votre code de nettoyage, puis l'exception persistera, pour être gérée par quelque chose qui sait quoi faire avec.

Autres conseils

" Enfin " est une déclaration de "Quelque chose que vous devez toujours faire pour vous assurer que l'état du programme est sain". En tant que tel, il est toujours bon d’en avoir un, s’il existe une possibilité que des exceptions gâchent le programme. Le compilateur s’efforce également de faire en sorte que votre code Finally soit exécuté.

"Catch" est une déclaration de "Je peux récupérer de cette exception". Vous ne devriez récupérer que des exceptions que vous pouvez vraiment corriger - catch sans arguments indique "Hé, je peux récupérer de n'importe quoi!", Ce qui est presque toujours faux.

S'il était possible de récupérer toutes les exceptions, il s'agirait vraiment d'une question sémantique concernant ce que vous déclarez être votre intention. Cependant, ce n’est pas le cas, et il est presque certain que les cadres supérieurs aux vôtres seront mieux équipés pour gérer certaines exceptions. En tant que tel, utilisez enfin votre code de nettoyage, mais laissez toujours des gestionnaires plus compétents s’occuper de la question.

Parce que quand cette seule ligne lève une exception, vous ne le sauriez pas.

Avec le premier bloc de code, l'exception sera simplement absorbée , le programme continuera à être exécuté même si l'état du programme est peut-être incorrect.

Avec le deuxième bloc, l'exception sera levée et fera apparaître des bulles , mais le reader.Close () est toujours garanti pour être exécuté.

Si une exception n'est pas attendue, ne mettez pas un bloc try..catch de la sorte, il sera difficile de déboguer plus tard lorsque le programme passera à un mauvais état et vous ne saurez pas pourquoi.

Enfin est exécuté quoi qu'il arrive. Donc, si votre bloc try a réussi, il s’exécutera. Si votre bloc try échoue, il exécutera ensuite le bloc catch, puis le bloc finally.

En outre, il est préférable d'essayer d'utiliser la construction suivante:

using (StreamReader reader=new  StreamReader("myfile.txt"))
{
}

Comme l'instruction using est automatiquement encapsulée dans un try / finally et le flux sera automatiquement fermé. (Vous aurez besoin de mettre un try / catch autour de l'instruction using si vous voulez réellement attraper l'exception).

Alors que les 2 blocs de code suivants sont équivalents, ils ne sont pas égaux.

try
{
  int i = 1/0; 
}
catch
{
  reader.Close();
  throw;
}

try
{
  int i = 1/0;
}
finally
{
  reader.Close();
}
  1. "finalement" est un code révélant l'intention. Vous déclarez au compilateur et aux autres programmeurs que ce code doit s’exécuter de toute manière.
  2. si vous avez plusieurs blocs catch et que vous avez un code de nettoyage, vous avez enfin besoin de. Sans cela, vous dupliqueriez votre code de nettoyage dans chaque bloc catch. (Principe SEC)

enfin les blocs sont spéciaux. Le CLR reconnaît et traite le code avec un bloc finally séparément des blocs catch, et le CLR déploie beaucoup d'efforts pour garantir qu'un bloc final sera toujours exécuté. Il n’ya pas que le sucre syntaxique du compilateur.

Je suis d'accord avec ce qui semble être le consensus ici: une "capture" vide est mauvaise, car elle masque toute exception qui aurait pu se produire dans le bloc try.

En outre, du point de vue de la lisibilité, lorsque je vois un bloc "try", je suppose qu’il y aura une instruction "catch" correspondante. Si vous utilisez uniquement un 'essai' afin de vous assurer que les ressources sont désallouées dans le bloc 'enfin', vous pouvez envisager le instruction 'utilisant' à la place:

using (StreamReader reader = new StreamReader('myfile.txt'))
{
    // do stuff here
} // reader.dispose() is called automatically

Vous pouvez utiliser l'instruction 'using' avec n'importe quel objet implémentant IDisposable. La méthode dispose () de l'objet est appelée automatiquement à la fin du bloc.

Le bloc try..finally lancera toujours les exceptions déclenchées. Tout ce que finally fait, c'est que le code de nettoyage est exécuté avant la levée de l'exception.

Le try..catch avec une capture vide consommera complètement toute exception et cachera le fait que cela s'est produit. Le lecteur sera fermé, mais rien ne dit si la bonne chose s’est produite. Et si votre intention était d'écrire i dans le fichier? Dans ce cas, vous ne pourrez pas accéder à cette partie du code et myfile.txt sera vide. Est-ce que toutes les méthodes en aval gèrent cela correctement? Quand vous verrez le fichier vide, pourrez-vous correctement deviner qu'il est vide car une exception a été levée? Mieux vaut jeter l’exception et faire savoir que vous faites quelque chose de mal.

Une autre raison est le try..catch fait comme ceci est complètement incorrect. Ce que vous dites en faisant cela est, "Peu importe ce qui se passe, je peux y faire face". Qu'en est-il de StackOverflowException , pouvez-vous nettoyer par la suite? Qu'en est-il de OutOfMemoryException ? En général, vous ne devez gérer que les exceptions que vous attendez et savez comment gérer.

Utilisez Try..Catch..Finally , si votre méthode sait comment gérer l'exception localement. L’exception se produit dans Try, Handled in Catch et ensuite, le nettoyage est terminé dans Finally.

Si votre méthode ne sait pas comment gérer l'exception mais a besoin d'un nettoyage, utilisez Try..Finally

.

Par ce biais, l’exception est propagée aux méthodes d’appel et gérée s’il existe des instructions Catch appropriées dans les méthodes d’appel. Si aucun gestionnaire d’exception ne figure dans la méthode actuelle ni dans aucune des méthodes d’appel, l’application se bloque.

Par Try..Finally , il est garanti que le nettoyage local est effectué avant de propager l'exception aux méthodes d'appel.

Si vous ne savez pas quel type d'exception capturer ou quoi en faire, il est inutile d'avoir une déclaration catch. Vous devriez simplement le laisser à un appelant plus haut placé qui pourrait avoir plus d'informations sur la situation et savoir ce qu'il faut faire.

Vous devriez toujours avoir une instruction finally là-bas au cas où il y aurait une exception, afin de pouvoir nettoyer les ressources avant que cette exception ne soit renvoyée à l'appelant.

Du point de vue de la lisibilité, il indique de manière plus explicite aux futurs lecteurs de code "que les éléments ici sont importants, qu’ils doivent être exécutés quoi qu’il se produise". C'est bon.

De plus, les déclarations de captures vides ont tendance à avoir une certaine "odeur". pour eux. Ils peuvent indiquer que les développeurs ne réfléchissent pas aux diverses exceptions pouvant se produire et à la manière de les gérer.

Enfin, c'est optionnel. Il n'y a aucune raison d'avoir un "Enfin". bloquer s'il n'y a pas de ressources à nettoyer.

Extrait de: ici

La levée et la capture des exceptions ne doivent pas se produire systématiquement dans le cadre de l'exécution réussie d'une méthode. Lors du développement de bibliothèques de classes, le code client doit avoir la possibilité de tester une condition d'erreur avant d'entreprendre une opération pouvant entraîner la génération d'une exception. Par exemple, System.IO.FileStream fournit une propriété CanRead qui peut être vérifiée avant d'appeler la méthode Read, empêchant ainsi la génération d'une exception potentielle, comme illustré dans l'extrait de code suivant:

Dim str As Stream = GetStream () Si (str.CanRead) Alors   'code pour lire le flux Fin si

La décision de vérifier ou non l'état d'un objet avant d'appeler une méthode particulière susceptible de déclencher une exception dépend de l'état attendu de l'objet. Si un objet FileStream est créé à l'aide d'un chemin de fichier qui devrait exister et d'un constructeur qui devrait renvoyer un fichier en mode lecture, la vérification de la propriété CanRead n'est pas nécessaire. l'incapacité de lire FileStream violerait le comportement attendu des appels de méthode effectués et une exception devrait être déclenchée. En revanche, si une méthode est documentée comme renvoyant une référence FileStream pouvant ou non être lisible, il est conseillé de vérifier la propriété CanRead avant de tenter de lire les données.

Pour illustrer l'impact sur les performances de l'utilisation d'un " exécution jusqu'à l'exception ". technique de codage peut provoquer, la performance d’un transtypage, qui lève une exception InvalidCastException si le transtypage échoue, est comparée à l’opérateur C # en tant qu’opérateur, qui renvoie la valeur null en cas d’échec de la transtypage. La performance des deux techniques est identique pour le cas où la conversion est valide (voir Test 8.05), mais pour le cas où la conversion est invalide et où l'utilisation d'un cast provoque une exception, l'utilisation d'un cast est 600 fois plus lente que l'utilisation du script. en tant qu'opérateur (voir test 8.06). L'impact haute performance de la technique de lancement d'exception inclut le coût de l'affectation, du lancement et de la capture de l'exception, ainsi que le coût du nettoyage ultérieur de l'objet exception, ce qui signifie que l'impact instantané du lancement d'une exception n'est pas si élevé. Au fur et à mesure que de nombreuses exceptions sont générées, le ramassage fréquent des ordures devient un problème. Par conséquent, l'impact global de l'utilisation fréquente d'une technique de codage avec levée des exceptions sera similaire à celui du test 8.05.

Il est déconseillé d’ajouter une clause catch uniquement pour réexaminer l’exception.

Enfin, vous pouvez nettoyer les ressources, même si votre instruction catch renvoie l’exception au programme appelant. Avec votre exemple contenant l'instruction de capture vide, il y a peu de différence. Toutefois, si vous êtes pris au piège, si vous faites un peu de traitement et jetez l’erreur, ou même si vous n’avez tout simplement pas de piège, l’appareil finira toujours par s’exécuter.

Eh bien, d’une part, c’est une mauvaise pratique d’attraper des exceptions que vous ne prenez pas la peine de gérer. Consultez le Chapitre 5 sur les performances .Net dans En cours d'amélioration. Évolutivité et performances des applications NET . Remarque secondaire, vous devriez probablement charger le flux à l'intérieur du bloc try. Ainsi, vous pouvez intercepter l'exception pertinente en cas d'échec. La création du flux en dehors du bloc try annule son objectif.

Parmi les nombreuses raisons probablement, les exceptions sont très lentes à exécuter. Vous pouvez facilement paralyser vos temps d'exécution si cela se produit souvent.

Le problème des blocs try / catch qui interceptent toutes les exceptions est que votre programme est maintenant dans un état indéterminé si une exception inconnue se produit. Cela va complètement à l'encontre de la règle d'échec rapide - vous ne voulez pas que votre programme continue si une exception se produit. L’essai / capture ci-dessus attraperait même OutOfMemoryExceptions, mais c’est définitivement un état dans lequel votre programme ne fonctionnera pas.

Les blocs try / finally vous permettent d'exécuter du code de nettoyage tout en échouant rapidement. Dans la plupart des cas, vous souhaitez uniquement intercepter toutes les exceptions au niveau global afin de pouvoir les consigner, puis les quitter.

La différence effective entre vos exemples est négligeable tant qu'aucune exception n'est levée.

Si, toutefois, une exception est levée dans la clause 'try', le premier exemple l’avalera complètement. Le deuxième exemple lève l’exception à l’étape suivante de la pile d’appel. Par conséquent, la différence entre les exemples cités est que l’un occulte complètement les exceptions (premier exemple) et que l’autre (deuxième exemple) conserve les informations relatives aux exceptions pour une éventuelle gestion ultérieure toujours en train d'exécuter le contenu de la clause 'finally'.

Si, par exemple, vous deviez placer du code dans la clause 'catch' du premier exemple qui renvoyait une exception (celle qui avait été initialement déclenchée ou une nouvelle), le code de nettoyage du lecteur ne s'exécuterait jamais. Enfin, exécute quel que soit ce qui se passe dans la clause 'catch'.

La différence principale entre "catch" et "finally" réside donc dans le fait que le contenu du bloc "finally" (à quelques rares exceptions près) peut être considéré comme garanti , même dans le face à une exception inattendue, alors que tout code suivant une clause "catch" (mais en dehors d’une clause "finally") ne comporterait pas une telle garantie.

Incidemment, Stream et StreamReader implémentent tous deux IDisposable et peuvent être encapsulés dans un bloc 'using'. Les blocs 'using' sont l'équivalent sémantique de try / finally (pas de 'catch'), votre exemple pourrait donc être plus simplement exprimé comme suit:

using (StreamReader reader = new  StreamReader("myfile.txt"))
{
  int i = 5 / 0;
}

... qui ferme et supprime l'instance StreamReader lorsqu'elle sort de la portée. J'espère que cela vous aidera.

essayer {…} attraper {} n’est pas toujours mauvais. Ce n'est pas un modèle courant, mais j'ai tendance à l'utiliser quand j'ai besoin d'arrêter des ressources quoi qu'il en soit, comme fermer des sockets (éventuellement) ouverts à la fin d'un thread.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top