J'ai vu des gens dire que c'est une mauvaise forme d'utiliser catch sans argument, surtout si ce catch 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();
}
Pour autant que je sache, la seule différence entre mettre du code de nettoyage dans un bloc finally et mettre du code de nettoyage après les blocs try..catch est si vous avez des instructions de retour dans votre bloc try (dans ce cas, le code de nettoyage dans exécuter, mais le code après le try..catch ne sera pas).
Sinon, qu'est-ce qui est si spécial finalement?
Réponses:
La grande différence est que cela
try...catch
va avaler l'exception, cachant le fait qu'une erreur s'est produite.try..finally
exécutera votre code de nettoyage, puis l'exception continuera, à gérer par quelque chose qui sait quoi en faire.la source
"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 y a une possibilité que des exceptions puissent perturber l'état du programme. Le compilateur va également très loin pour s'assurer que votre code Enfin est exécuté.
"Catch" est une déclaration de "Je peux récupérer de cette exception". Vous ne devez récupérer que des exceptions que vous pouvez vraiment corriger - capture sans arguments dit "Hé, je peux récupérer de tout!", Ce qui est presque toujours faux.
S'il était possible de se remettre de chaque exception, alors ce serait vraiment un petit problème sémantique sur ce que vous déclarez être votre intention. Cependant, ce n'est pas le cas et les cadres au-dessus du vôtre seront certainement mieux équipés pour gérer certaines exceptions. En tant que tel, utilisez enfin, exécutez votre code de nettoyage gratuitement, mais laissez encore plus de gestionnaires compétents gérer le problème.
la source
Parce que lorsque cette seule ligne lève une exception, vous ne le saurez pas.
Avec le premier bloc de code, l'exception sera simplement absorbée , le programme continuera à s'exécuter même lorsque l'état du programme pourrait être incorrect.
Avec le deuxième bloc, l'exception sera levée et bouillonnera mais le fonctionnement
reader.Close()
est toujours garanti.Si une exception n'est pas attendue, alors ne mettez pas de bloc try..catch juste ainsi, il sera difficile de déboguer plus tard lorsque le programme est entré dans un mauvais état et vous ne savez pas pourquoi.
la source
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 alors le bloc catch, puis le bloc finally.
En outre, il est préférable d'essayer d'utiliser la construction suivante:
Comme l'instruction using est automatiquement encapsulée dans un essai / enfin et le flux sera automatiquement fermé. (Vous devrez mettre un try / catch autour de l'instruction using si vous voulez réellement attraper l'exception).
la source
Bien que les 2 blocs de code suivants soient équivalents, ils ne sont pas égaux.
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 va très loin pour garantir qu'un bloc finally s'exécutera toujours. Ce n'est pas seulement du sucre syntaxique du compilateur.
la source
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 «essayer», je suppose qu'il y aura une déclaration «catch» correspondante. Si vous utilisez uniquement un «essai» afin de vous assurer que les ressources sont désallouées dans le bloc «finalement», vous pouvez plutôt considérer l' instruction «using» :
Vous pouvez utiliser l'instruction 'using' avec n'importe quel objet qui implémente IDisposable. La méthode dispose () de l'objet est appelée automatiquement à la fin du bloc.
la source
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 après ce nettoyage est effectué dans Finalement.Si votre méthode ne sait pas comment gérer l'exception mais a besoin d'un nettoyage une fois qu'elle s'est produite, utilisez
Try..Finally
Par cela, 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. S'il n'y a pas de gestionnaire d'exceptions dans la méthode actuelle ou l'une des méthodes d'appel, l'application se bloque.
Par
Try..Finally
elle est assurée que le nettoyage local est fait avant de propager l'exception aux méthodes d'appel.la source
Le bloc try..finally lèvera toujours toutes les exceptions levées. Tout
finally
suffit de s'assurer que le code de nettoyage est exécuté avant que l'exception ne soit levée.Le try..catch avec un catch vide consommera complètement toute exception et masquera le fait que cela s'est produit. Le lecteur sera fermé, mais on ne sait pas 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 monfichier.txt sera vide. Toutes les méthodes en aval gèrent-elles correctement cela? Lorsque vous verrez le fichier vide, pourrez-vous deviner correctement qu'il est vide car une exception a été levée? Mieux vaut lever l'exception et faire savoir que vous faites quelque chose de mal.
Une autre raison est que le try..catch fait comme ceci est complètement incorrect. Ce que vous dites en faisant cela, c'est: «Peu importe ce qui se passe, je peux le gérer.» Qu'en est-il
StackOverflowException
, pouvez-vous nettoyer après cela? Et alorsOutOfMemoryException
? En général, vous ne devez gérer que les exceptions que vous attendez et savoir comment gérer.la source
Si vous ne savez pas quel type d'exception intercepter ou quoi en faire, il est inutile d'avoir une instruction catch. Vous devriez simplement le laisser à un appelant supérieur qui peut avoir plus d'informations sur la situation pour savoir quoi faire.
Vous devriez toujours avoir une instruction finally là-dedans au cas où il y aurait une exception, afin que vous puissiez nettoyer les ressources avant que cette exception ne soit levée à l'appelant.
la source
Du point de vue de la lisibilité, il est plus explicite de dire aux futurs lecteurs de code "ce genre de choses ici est important, cela doit être fait quoi qu'il arrive." C'est bon.
De plus, les déclarations de captures vides ont tendance à avoir une certaine "odeur". Ils peuvent être un signe que les développeurs ne réfléchissent pas aux diverses exceptions qui peuvent survenir et à la façon de les gérer.
la source
Enfin est facultatif - il n'y a aucune raison d'avoir un bloc "Enfin" s'il n'y a pas de ressources à nettoyer.
la source
Extrait de: ici
La levée et la capture d'exceptions ne devraient pas se produire régulièrement 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 le déclenchement 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 une exception potentielle d'être déclenchée, comme illustré dans l'extrait de code suivant:
Dim str As Stream = GetStream () If (str.CanRead) Then 'code pour lire le flux End If
La décision de vérifier ou non l'état d'un objet avant d'invoquer 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 doit exister et d'un constructeur qui doit retourner un fichier en mode lecture, la vérification de la propriété CanRead n'est pas nécessaire; l'incapacité de lire le FileStream serait une violation du comportement attendu des appels de méthode effectués et une exception devrait être levée. En revanche, si une méthode est documentée comme renvoyant une référence FileStream qui peut 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 que l'utilisation d'une technique de codage "exécuter jusqu'à exception" peut entraîner, les performances d'un cast, qui lève une InvalidCastException si le cast échoue, sont comparées à l'opérateur C # en tant qu'opérateur, qui renvoie des valeurs nulles en cas d'échec d'un cast. Les performances des deux techniques sont identiques dans le cas où le plâtre est valide (voir test 8.05), mais dans le cas où le plâtre n'est pas valide et l'utilisation d'un plâtre provoque une exception, l'utilisation d'un plâtre est 600 fois plus lente que l'utilisation du comme opérateur (voir Test 8.06). L'impact de haute performance de la technique de levée d'exception inclut le coût d'allocation, de levée et de capture de l'exception et le coût de la récupération de place ultérieure de l'objet d'exception, ce qui signifie que l'impact instantané du lancement d'une exception n'est pas si élevé. Comme plus d'exceptions sont levées,
la source
C'est une mauvaise pratique d'ajouter une clause catch juste pour annuler l'exception.
la source
Si vous lisez C # pour les programmeurs, vous comprendrez que le bloc finally a été conçu pour optimiser une application et éviter les fuites de mémoire.
Par exemple, lorsque vous ouvrez une connexion de fichier ou de base de données, votre ordinateur allouera de la mémoire pour traiter cette transaction, et cette mémoire ne sera conservée que si la commande supprimée ou fermée a été exécutée. mais si au cours de la transaction, une erreur s'est produite, la commande en cours se terminera, sauf si elle était à l'intérieur du
try.. finally..
bloc.catch
était différentfinally
dans le sens où, catch a été conçu pour vous permettre de gérer / gérer ou d'interpréter l'erreur elle-même. Considérez-le comme une personne qui vous dit "hé j'ai attrapé des méchants, que voulez-vous que je leur fasse?" while afinally
été conçu pour vous assurer que vos ressources étaient correctement placées. Pensez à quelqu'un qui, qu'il y ait ou non des méchants, s'assurera que votre propriété est toujours en sécurité.Et vous devriez permettre à ces deux-là de travailler ensemble pour de bon.
par exemple:
la source
Avec enfin, vous pouvez nettoyer les ressources, même si votre instruction catch lève l'exception au programme appelant. Avec votre exemple contenant l'instruction catch vide, il y a peu de différence. Cependant, si dans votre capture, vous effectuez un traitement et lancez l'erreur, ou même si vous n'avez même pas de capture du tout, le fichier sera toujours exécuté.
la source
Eh bien, pour commencer, 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 à partir de l' amélioration des performances et de l'évolutivité des applications .NET . Remarque: vous devriez probablement charger le flux à l'intérieur du bloc try, de cette façon, vous pouvez intercepter l'exception pertinente en cas d'échec. La création du flux en dehors du bloc try va à l'encontre de son objectif.
la source
Parmi probablement de nombreuses raisons, les exceptions sont très lentes à exécuter. Vous pouvez facilement paralyser vos temps d'exécution si cela se produit souvent.
la source
Le problème avec les 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 intercepterait même OutOfMemoryExceptions, mais c'est certainement 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 journaliser, puis quitter.
la source
La différence effective entre vos exemples est négligeable tant qu'aucune exception n'est levée.
Si, cependant, une exception est levée dans la clause 'try', le premier exemple l'avalera complètement. Le deuxième exemple lèvera l'exception à l'étape suivante de la pile d'appels, de sorte que la différence dans les exemples indiqués est que l'un masque complètement toutes les exceptions (premier exemple), et l'autre (deuxième exemple) conserve les informations d'exception pour une gestion ultérieure potentielle tout en exécutant toujours le contenu de la clause «enfin».
Si, par exemple, vous deviez mettre du code dans la clause 'catch' du premier exemple qui a levé une exception (soit celle qui a été déclenchée initialement, soit une nouvelle), le code de nettoyage du lecteur ne s'exécutera jamais. S'exécute enfin indépendamment de ce qui se passe dans la clause «catch».
Ainsi, la principale différence entre «catch» et «finalement» est que le contenu du bloc «enfin» (à quelques rares exceptions près) peut être considéré comme garanti pour s'exécuter, même face à une exception inattendue, tandis que tout code suivant une clause «catch» (mais en dehors d'une clause «finalement») ne comporterait pas une telle garantie.
Soit dit en passant, Stream et StreamReader implémentent tous deux IDisposable et peuvent être encapsulés dans un bloc `` using ''. 'Utiliser' les blocs est l'équivalent sémantique de try / finally (pas de 'catch'), donc votre exemple pourrait être exprimé de manière plus laconique:
... qui fermera et supprimera l'instance StreamReader lorsqu'elle sortira du cadre. J'espère que cela t'aides.
la source
essayer {…} catch {} n'est pas toujours mauvais. Ce n'est pas un modèle courant, mais j'ai tendance à l'utiliser lorsque j'ai besoin d'arrêter des ressources, quoi qu'il arrive, comme fermer un (éventuellement) sockets ouverts à la fin d'un thread.
la source