web-dev-qa-db-fra.com

Blocs de capture vides

Je me heurte parfois à des situations où j'ai besoin d'attraper une exception si elle est levée sans jamais rien faire avec. En d'autres termes, une exception peut se produire, mais cela n'a pas d'importance.

J'ai récemment lu cet article sur une chose similaire: http://c2.com/cgi/wiki?EmptyCatchClause

Cette personne raconte comment le commentaire de

// should never occur 

est une odeur de code et ne doit jamais apparaître dans le code. Ils expliquent ensuite comment le commentaire

// don't care if it happens

est entièrement différent et je rencontre moi-même des situations comme celle-ci. Par exemple, lorsque j'envoie un e-mail, je fais quelque chose de similaire à ceci:

var addressCollection = new MailAddressCollection();
foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (Exception)
    {
        // Do nothing - if an invalid email occurs continue and try to add the rest
    }
}

Maintenant, vous pensez peut-être que faire cela est une mauvaise idée car vous voudriez retourner à l'utilisateur et expliquer qu'un ou plusieurs messages n'ont pas pu être envoyés au destinataire. Mais que faire si c'est juste une adresse CC? C'est moins important et vous voudrez peut-être quand même envoyer le message même si l'une de ces adresses n'était pas valide (peut-être juste une faute de frappe).

Ai-je donc raison d'utiliser un bloc catch vide ou existe-t-il une meilleure alternative que je ne connais pas?

33
Serberuss

Vous avez tout à fait raison d'utiliser un bloc catch vide si vous ne voulez vraiment rien faire lorsqu'un certain type d'exception se produit. Vous pouvez améliorer votre exemple en n'attrapant que les types d'exceptions que vous attendez , et que vous savez ignorer en toute sécurité. En attrapant Exception, vous pouvez masquer les bogues et rendre plus difficile le débogage de votre programme.

Une chose à garder à l'esprit concernant la gestion des exceptions: il y a une grande différence entre les exceptions qui sont utilisées pour signaler une condition d'erreur externe à votre programme, qui est attendue se produire au moins parfois, et les exceptions qui indiquent une erreur de programmation. Un exemple du 1er serait une exception indiquant qu'un e-mail n'a pas pu être remis car la connexion a expiré, ou un fichier n'a pas pu être enregistré car il n'y avait pas d'espace disque. Un exemple du 2ème serait une exception indiquant que vous avez essayé de passer le mauvais type d'argument à une méthode, ou que vous avez essayé d'accéder à un élément de tableau hors limites.

Pour le 2ème (erreur de programmation), ce serait une grosse erreur de simplement "avaler" l'exception. La meilleure chose à faire est généralement de consigner une trace de pile, puis d'afficher un message d'erreur indiquant à l'utilisateur qu'une erreur interne s'est produite et qu'il doit renvoyer ses journaux aux développeurs (c'est-à-dire vous). Ou pendant le développement, vous pouvez simplement lui faire imprimer une trace de pile sur la console et planter le programme.

Pour le 1er (problème externe), il n'y a pas de règle sur ce qu'il faut faire. Tout dépend des détails de l'application. Si vous voulez ignorer une certaine condition et continuer, faites-le.

EN GÉNÉRAL:

C'est bien que vous lisiez des livres et des articles techniques. Vous pouvez en apprendre beaucoup en le faisant. Mais n'oubliez pas, en lisant, que vous trouverez de nombreux conseils de personnes disant que faire telle ou telle chose est toujours mal ou toujours à droite. Souvent, ces opinions frisent la religion. [~ # ~] jamais [~ # ~] croire que faire les choses d'une certaine manière est absolument "juste" parce qu'un livre ou un article (ou une réponse SO SO ... <cough>) vous l'a dit. Il existe des exceptions à chaque règle, et les personnes qui écrivent ces articles ne connaissent pas les détails de votre demande. Tu fais. Assurez-vous que ce que vous lisez a du sens, et si ce n'est pas le cas, faites-vous confiance.

72
Alex D

Un bloc de capture vide est bien au bon endroit - bien que d'après votre échantillon, je dirais que vous devriez cétagoriquement PAS utilisez catch (Exception). Vous devez plutôt intercepter l'exception explicite qui devrait se produire.

La raison en est que si vous avalez tout, vous avalerez également des défauts critiques auxquels vous ne vous attendiez pas. Il y a un monde de différence entre "Je ne peux pas envoyer à cette adresse e-mail" et "votre ordinateur manque d'espace disque". Vous ne voulez pas continuer à essayer d'envoyer les 10000 prochains e-mails si vous manquez d'espace disque!

La différence entre "ne devrait pas se produire" et "ne se soucie pas si cela se produit" est que, si cela "ne devrait pas se produire", alors quand cela se produit arrive, vous ne voulez pas l'avaler en silence! S'il s'agit d'une condition que vous ne vous attendiez pas à rencontrer, vous voudriez généralement que votre application plante (ou au moins se termine proprement et enregistre abondamment ce qui s'est passé) afin que vous puissiez identifier cette condition impossible.

18
Dan Puzey

Si une exception ne doit jamais être levée, il est inutile de l'attraper - cela ne devrait jamais arriver et si c'est le cas, vous devez le savoir.

S'il y a des scénarios spécifiques qui peuvent provoquer une défaillance avec laquelle vous êtes d'accord, vous devez attraper et tester ces scénarios spécifiques et relancer dans tous les autres cas, par exemple

foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (EmailNotSentException ex)
    {
        if (IsCausedByMissingCcAddress(ex))
        {
            // Handle this case here e.g. display a warning or just nothing
        }
        else
        {
            throw;
        }
    }
}

Notez que le code ci-dessus intercepte des exceptions spécifiques (si fictives) plutôt que d'attraper Exception. Je peux penser à très peu de cas où il est légitime d'attraper Exception au lieu d'attraper un type d'exception spécifique que vous attendez à être levé.

7
Justin

La plupart des autres réponses donnent de bonnes raisons quand il serait correct d'attraper l'exception, mais de nombreuses classes prennent en charge les moyens de ne pas lever l'exception du tout.

Souvent, ces méthodes auront le préfixe Try devant elles. Au lieu de lever une exception, la fonction renvoie un booléen indiquant si la tâche a réussi.

Un bon exemple de ceci est Parse vs TryParse

string s = "Potato";
int i;
if(int.TryParse(s, out i))
{
    //This code is only executed if "s" was parsed succesfully.
    aCollectionOfInts.Add(i);
}

Si vous essayez la fonction ci-dessus dans une boucle et la comparez avec son équivalent Parse + Catch, la méthode TryParse sera beaucoup plus rapide.

5

L'utilisation d'un bloc catch vide avale simplement l'exception, je le gérerais toujours, même s'il vous signale qu'un Exception s'est produit.

Attraper également le générique Exception est une mauvaise pratique car il peut cacher des bogues dans votre application. Par exemple, vous avez peut-être intercepté une exception ArgumentOutOfRange dont vous ne saviez pas qu'il se passait, puis vous l'avez avalée (c'est-à-dire que vous n'avez rien fait avec).

2
Darren