Comment utiliser try catch pour la gestion des exceptions est la meilleure pratique


201

tout en conservant le code de mon collègue, même de quelqu'un qui prétend être un développeur senior, je vois souvent le code suivant:

try
{
  //do something
}
catch
{
  //Do nothing
}

ou parfois ils écrivent des informations de journalisation dans des fichiers journaux comme le try catchbloc suivant

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

Je me demande simplement si ce qu'ils ont fait est la meilleure pratique? Cela me rend confus car, selon moi, les utilisateurs devraient savoir ce qui se passe avec le système.

Veuillez me donner quelques conseils.


128
L'extrait n ° 1 est inacceptable dans 99,999% des cas.
leppie

22
Afficher une exception directement à l'utilisateur n'est jamais une bonne idée, principalement pour deux raisons: 1. s'il s'agit d'un utilisateur habituel, il sera ennuyé de lire un message d'erreur qui en dit très peu pour lui. 2. s'il est soi-disant pirate, il peut obtenir des informations utiles. La meilleure pratique, l'OMI, consiste à consigner les exceptions et à afficher un message d'erreur convivial.
Leri

4
@leppie Si quelque chose d'inattendu se produit (comme NullReferenceou ArgumentNullqui ne fait pas partie du flux d'application), cela signifie qu'il y a un bogue qui doit être corrigé, donc les enregistrer vous aidera à déboguer votre code beaucoup plus rapidement.
Leri

14
L'utilisation d'un bloc try-catch pour masquer une exception est généralement le résultat d'une programmation paresseuse. C'est un raccourci qui est souvent utilisé au lieu d'écrire du code de validation pour tester les entrées. Il arrive très parfois qu'une exception se produise qui n'affecte pas le fonctionnement de votre code, et le masquer comme ceci peut être OK. C'est assez rare cependant.
Corey

12
@Toan, eh bien, s'il s'agit d'un travail par lots, j'attrape au niveau supérieur (principal) pour me connecter, puis je rejette pour déclencher une alarme indiquant que le travail s'est terminé anormalement. S'il s'agit d'une application Web, je laisse la bulle d'exception à un gestionnaire global, je me connecte, puis je redirige l'utilisateur vers un écran d'erreur. Votre scénario de cas d'utilisation dicte ce que vous faites avec cette exception après l'avoir connectée ou autrement gérée.
Anthony Pegram

Réponses:


300

Ma stratégie de gestion des exceptions est la suivante:

  • Pour intercepter toutes les exceptions non gérées en se connectant au Application.ThreadException event, alors décidez:

    • Pour une application d'interface utilisateur: pour l'afficher à l'utilisateur avec un message d'excuses (winforms)
    • Pour un service ou une application console: connectez-le à un fichier (service ou console)

Ensuite, je joins toujours chaque morceau de code exécuté en externe dans try/catch:

  • Tous les événements déclenchés par l'infrastructure Winforms (Load, Click, SelectedChanged ...)
  • Tous les événements déclenchés par des composants tiers

Ensuite, je joins à «essayer / attraper»

  • Toutes les opérations que je connais peuvent ne pas fonctionner tout le temps (opérations IO, calculs avec une division zéro potentielle ...). Dans un tel cas, je lance un nouveau ApplicationException("custom message", innerException)pour garder une trace de ce qui s'est vraiment passé

De plus, je fais de mon mieux pour trier correctement les exceptions . Il existe des exceptions qui:

  • doivent être montrés à l'utilisateur immédiatement
  • nécessitent un traitement supplémentaire pour rassembler les éléments lorsqu'ils se produisent afin d'éviter les problèmes de cascade (par exemple: mettez .EndUpdate dans la finallysection pendant un TreeViewremplissage)
  • l'utilisateur s'en fiche, mais il est important de savoir ce qui s'est passé. Je les enregistre donc toujours:

    • Dans le journal des événements
    • ou dans un fichier .log sur le disque

Il est recommandé de concevoir certaines méthodes statiques pour gérer les exceptions dans les gestionnaires d'erreurs de niveau supérieur de l'application.

Je me force également à essayer de:

  • N'oubliez pas que TOUTES les exceptions sont propagées au niveau supérieur . Il n'est pas nécessaire de placer des gestionnaires d'exceptions partout.
  • Les fonctions appelées réutilisables ou approfondies n'ont pas besoin d'afficher ou de consigner les exceptions: elles sont soit propagées automatiquement, soit renvoyées avec certains messages personnalisés dans mes gestionnaires d'exceptions.

Alors finalement:

Mauvais:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Inutile:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Avoir un essai enfin sans prise est parfaitement valable:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Ce que je fais au plus haut niveau:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Ce que je fais dans certaines fonctions appelées:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Il y a beaucoup à voir avec la gestion des exceptions (exceptions personnalisées), mais les règles que j'essaie de garder à l'esprit sont suffisantes pour les applications simples que je fais.

Voici un exemple de méthodes d'extensions pour gérer les exceptions interceptées de manière confortable. Ils sont implémentés de manière à pouvoir être enchaînés ensemble, et il est très facile d'ajouter votre propre traitement des exceptions interceptées.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}

98
catch(Exception ex) { throw ex; }en C # est pire que redondant (quel que soit le type d'exception que vous attrapez). Pour recommencer, utilisez throw;. Avec le premier, l'exception semblera provenir de votre throw exalors qu'avec le second, il proviendra correctement de la throwdéclaration d' origine .
un CVn

2
Pourquoi accrochez-vous l' Application.ThreadExceptionévénement et encapsulez chaque exception avec un catch(Exception ex) {ex.Log(ex);}. Je conviendrais probablement que le premier est une excellente pratique, mais le second ajoute le risque de dupliquer vos journaux d'erreurs et cache que l'exception s'est produite. Est également throw extrès très mauvais.
Keith

1
J'ai compris catch (Exception ex) {throw ex; } être inutile. Je suppose donc que "redondant" n'est pas le meilleur mot pour dire "Ne fais pas ça". C'est pourquoi j'ai changé un peu le post pour mieux dire que les deux premiers exemples de catch catch doivent être évités.
Larry

3
Grande et constructive réponse, j'ai surtout apprécié la phrase Only air :) Et merci pour l' Application.ThreadExceptionévénement, je n'étais pas au courant, très utile.
Mahdi Tahsildari


61

La meilleure pratique est que la gestion des exceptions ne doit jamais masquer les problèmes . Cela signifie que les try-catchblocs doivent être extrêmement rares.

Il y a 3 circonstances où l'utilisation d'un a du try-catchsens.

  1. Traitez toujours les exceptions connues aussi bas que possible. Cependant, si vous vous attendez à une exception, il est généralement préférable de la tester en premier. Par exemple, l'analyse syntaxique, la mise en forme et les exceptions arithmétiques sont presque toujours mieux gérées par les vérifications logiques en premier, plutôt que par un spécifique try-catch.

  2. Si vous devez faire quelque chose sur une exception (par exemple, journaliser ou annuler une transaction), relancez l'exception.

  3. Traitez toujours les exceptions inconnues aussi haut que vous le pouvez - le seul code qui devrait consommer une exception et non la renvoyer devrait être l'interface utilisateur ou l'API publique.

Supposons que vous vous connectez à une API distante, ici vous savez que vous devez vous attendre à certaines erreurs (et que vous avez des choses à faire dans ces circonstances), c'est donc le cas 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Notez qu'aucune autre exception n'est interceptée, car elles ne sont pas attendues.

Supposons maintenant que vous essayez d'enregistrer quelque chose dans la base de données. Nous devons l'annuler en cas d'échec, nous avons donc le cas 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Notez que nous rejetons à nouveau l'exception - le code plus haut doit toujours savoir que quelque chose a échoué.

Enfin, nous avons l'interface utilisateur - ici, nous ne voulons pas avoir d'exceptions complètement non gérées, mais nous ne voulons pas non plus les cacher. Voici un exemple du cas 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Cependant, la plupart des frameworks API ou UI ont des façons génériques de faire le cas 3. Par exemple, ASP.Net a un écran d'erreur jaune qui vide les détails de l'exception, mais qui peut être remplacé par un message plus générique dans l'environnement de production. Il est préférable de les suivre car cela vous permet d'économiser beaucoup de code, mais aussi parce que la journalisation et l'affichage des erreurs doivent être des décisions de configuration plutôt que codées en dur.

Tout cela signifie que le cas 1 (exceptions connues) et le cas 3 (gestion unique de l'interface utilisateur) ont tous les deux de meilleurs modèles (éviter l'erreur attendue ou la gestion de l'erreur manuelle vers l'interface utilisateur).

Même le cas 2 peut être remplacé par de meilleurs modèles, par exemple les étendues de transaction ( usingblocs qui annulent toute transaction non validée pendant le bloc), il est plus difficile pour les développeurs de se tromper sur le modèle des meilleures pratiques.

Par exemple, supposons que vous ayez une application ASP.Net à grande échelle. La journalisation des erreurs peut être via ELMAH , l'affichage des erreurs peut être un YSoD informatif localement et un joli message localisé en production. Les connexions à la base de données peuvent toutes se faire via des étendues de transaction et des usingblocs. Vous n'avez pas besoin d'un seul try-catchbloc.

TL; DR: La meilleure pratique est en fait de ne pas utiliser du tout de try-catchblocs.


4
@Jorj, vous devriez lire l'intégralité du message, et si vous n'êtes toujours pas d'accord, il serait peut-être plus constructif de contrer l'un de mes arguments à l'appui plutôt que de simplement déclarer que vous n'aimez pas ma conclusion. Il y a presque toujours un meilleur modèle que try-catch- il peut (très occasionnellement) être utile et je ne dis pas que vous ne devriez jamais les utiliser, mais 99% du temps, il y a une meilleure façon.
Keith

La meilleure réponse de loin - presque tous les types de développement .net ont un HANDLER d'une sorte qui est beaucoup mieux adapté pour traiter les exceptions au niveau mondial, ce qui rend beaucoup plus facile de les gérer de manière cohérente ainsi que de le laisser simplement exploser en développement (pourquoi quelqu'un voudrait-il creuser dans un fichier journal pour une trace de pile ??) @Kieth, je dirigerais avec votre TLDR et ajouterais quelques exemples de gestionnaires globaux (c.-à-d. ThreadException, Application_Error, etc.). Par tous les moyens, attrapez des erreurs SPÉCIFIQUES, mais il est fou d'enrouler une méthode dans un try / catch / log
b_levitt

34

Une exception est une erreur de blocage .

Tout d'abord, la meilleure pratique devrait être de ne pas lever d'exceptions pour tout type d'erreur, sauf s'il s'agit d'une erreur de blocage .

Si l'erreur est bloquante , lancez l'exception. Une fois que l'exception est déjà levée, il n'est pas nécessaire de la cacher car elle est exceptionnelle; faites-le savoir à l'utilisateur (vous devez reformater toute l'exception en quelque chose d'utile pour l'utilisateur dans l'interface utilisateur).

Votre travail en tant que développeur de logiciels consiste à éviter un cas exceptionnel où certains paramètres ou situations d'exécution peuvent se terminer par une exception. Autrement dit, les exceptions ne doivent pas être mises en sourdine, mais elles doivent être évitées .

Par exemple, si vous savez qu'une entrée entière peut avoir un format non valide, utilisez int.TryParseplutôt que int.Parse. Il y a beaucoup de cas où vous pouvez le faire au lieu de simplement dire "si cela échoue, jetez simplement une exception".

Lancer des exceptions coûte cher.

Si, après tout, une exception est levée, au lieu d'écrire l'exception dans le journal une fois qu'elle a été levée, l'une des meilleures pratiques consiste à l'attraper dans un gestionnaire d'exceptions de première chance . Par exemple:

  • ASP.NET: Global.asax Application_Error
  • Autres: événement AppDomain.FirstChanceException .

Ma position est que les tentatives / captures locales sont mieux adaptées pour gérer des cas spéciaux où vous pouvez traduire une exception en une autre, ou lorsque vous voulez la "couper" pour un cas très, très, très, très, très spécial (un bug de bibliothèque levant une exception sans rapport que vous devez désactiver pour contourner tout le bogue).

Pour le reste des cas:

  • Essayez d'éviter les exceptions.
  • Si ce n'est pas possible: gestionnaires d'exceptions de première chance.
  • Ou utilisez un aspect PostSharp (AOP).

Répondre à @thewhiteambit sur un commentaire ...

@thewhiteambit a déclaré:

Les exceptions ne sont pas des erreurs fatales, ce sont des exceptions! Parfois, ce ne sont même pas des erreurs, mais les considérer comme des erreurs fatales est une compréhension complètement fausse de ce que sont les exceptions.

Tout d'abord, comment une exception ne peut-elle même pas être une erreur?

  • Aucune connexion à la base de données => exception.
  • Format de chaîne non valide pour analyser une exception de type =>
  • Essayer d'analyser JSON et alors que l'entrée n'est pas en fait JSON => exception
  • Argument nullalors que l'objet était attendu => exception
  • Certaines bibliothèques ont un bug => lève une exception inattendue
  • Il y a une connexion socket et elle est déconnectée. Ensuite, vous essayez d'envoyer un message => exception
  • ...

Nous pourrions énumérer 1k cas où une exception est levée, et après tout, l'un des cas possibles sera une erreur .

Une exception est une erreur, car à la fin de la journée, c'est un objet qui collecte des informations de diagnostic - il a un message et cela se produit lorsque quelque chose ne va pas.

Personne ne lèverait une exception lorsqu'il n'y a pas de cas exceptionnel. Les exceptions devraient bloquer les erreurs, car une fois qu'elles sont levées, si vous n'essayez pas de tomber dans l' utilisation try / catch et les exceptions pour implémenter le flux de contrôle, cela signifie que votre application / service arrêtera l'opération qui est entrée dans un cas exceptionnel .

Aussi, je suggère à tout le monde de vérifier le paradigme fail-fast publié par Martin Fowler (et écrit par Jim Shore) . C'est ainsi que j'ai toujours compris comment gérer les exceptions, même avant d'arriver à ce document il y a quelque temps.

[...] les considérer comme des erreurs fatales est une compréhension complètement fausse de ce que sont les exceptions.

Habituellement, les exceptions réduisent certains flux d'opérations et sont traitées pour les convertir en erreurs compréhensibles par l'homme. Ainsi, il semble qu'une exception soit en fait un meilleur paradigme pour gérer les cas d'erreur et y travailler pour éviter un plantage complet de l'application / service et informer l'utilisateur / consommateur que quelque chose s'est mal passé.

Plus de réponses sur @thewhiteambit

Par exemple, en cas de connexion à une base de données manquante, le programme peut exceptionnellement continuer à écrire dans un fichier local et envoyer les modifications à la base de données une fois qu'elle est à nouveau disponible. Votre transtypage String-to-Number invalide pourrait être essayé à nouveau d'analyser avec une interprétation locale de la langue sur Exception, comme lorsque vous essayez la langue anglaise par défaut pour analyser ("1,5") échoue et vous essayez à nouveau avec une interprétation allemande qui est complètement bien parce que nous utilisons une virgule au lieu du point comme séparateur. Vous voyez que ces exceptions ne doivent même pas être bloquantes, elles ont seulement besoin d'une gestion des exceptions.

  1. Si votre application peut fonctionner hors ligne sans conserver les données dans la base de données, vous ne devez pas utiliser d' exceptions , car l'implémentation du flux de contrôle à l'aide try/catchest considérée comme un anti-modèle. Le travail hors ligne est un cas d'utilisation possible, vous implémentez donc un flux de contrôle pour vérifier si la base de données est accessible ou non, vous n'attendez pas qu'elle soit inaccessible .

  2. L' analyse est également un cas attendu ( pas un CAS EXCEPTIONNEL ). Si vous vous y attendez, vous n'utilisez pas d'exceptions pour contrôler le flux! . Vous obtenez des métadonnées de l'utilisateur pour savoir quelle est sa culture et vous utilisez des formateurs pour cela! .NET prend également en charge cet environnement et d'autres, et une exception car la mise en forme des nombres doit être évitée si vous vous attendez à une utilisation spécifique à la culture de votre application / service .

Une exception non gérée devient généralement une erreur, mais les exceptions elles-mêmes ne sont pas codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Cet article n'est qu'un avis ou un point de vue de l'auteur.

Étant donné que Wikipédia peut également être uniquement l'opinion des auteurs d'articules, je ne dirais pas que c'est le dogme , mais vérifiez ce que l'article Codage par exception dit quelque part dans un paragraphe:

[...] L'utilisation de ces exceptions pour gérer des erreurs spécifiques qui surviennent pour continuer le programme est appelée codage par exception. Cet anti-modèle peut rapidement dégrader les performances et la maintenabilité du logiciel.

Cela dit aussi quelque part:

Utilisation d'exception incorrecte

Souvent, le codage par exception peut entraîner d'autres problèmes dans le logiciel avec une utilisation d'exception incorrecte. En plus d'utiliser la gestion des exceptions pour un problème unique, une utilisation incorrecte des exceptions va plus loin en exécutant du code même après le déclenchement de l'exception. Cette mauvaise méthode de programmation ressemble à la méthode goto dans de nombreux langages logiciels mais ne se produit qu'après détection d'un problème dans le logiciel.

Honnêtement, je crois qu'un logiciel ne peut pas être développé sans prendre au sérieux les cas d'utilisation. Si tu le sais ...

  • Votre base de données peut se déconnecter ...
  • Certains fichiers peuvent être verrouillés ...
  • Certains formats peuvent ne pas être pris en charge ...
  • Une validation de domaine peut échouer ...
  • Votre application devrait fonctionner en mode hors ligne ...
  • quel que soit le cas d'utilisation ...

... vous n'utiliserez pas d'exceptions pour cela . Vous prendriez en charge ces cas d'utilisation à l'aide d'un flux de contrôle régulier.

Et si un cas d'utilisation inattendu n'est pas couvert, votre code échouera rapidement, car il lèvera une exception . D'accord, car une exception est un cas exceptionnel .

D'autre part, et enfin, parfois, vous couvrez des cas exceptionnels en lançant des exceptions attendues , mais vous ne les lancez pas pour implémenter le flux de contrôle. Vous le faites parce que vous souhaitez informer les couches supérieures que vous ne prenez pas en charge certains cas d'utilisation ou que votre code ne fonctionne pas avec certains arguments ou données / propriétés d'environnement donnés.


6

La seule fois où vous devez inquiéter vos utilisateurs de ce qui s'est passé dans le code, c'est s'ils peuvent ou doivent faire quelque chose pour éviter le problème. S'ils peuvent modifier les données d'un formulaire, appuyez sur un bouton ou modifiez un paramètre d'application afin d'éviter le problème, puis faites-le-leur savoir. Mais les avertissements ou les erreurs que l'utilisateur n'a pas la possibilité d'éviter ne font que lui faire perdre confiance en votre produit.

Les exceptions et les journaux sont pour vous, le développeur, pas votre utilisateur final. Comprendre la bonne chose à faire lorsque vous interceptez chaque exception est bien mieux que d'appliquer simplement une règle d'or ou de s'appuyer sur un filet de sécurité à l'échelle de l'application.

Le codage insensé est le SEUL type de mauvais codage. Le fait que vous sentiez qu'il y a quelque chose de mieux à faire dans ces situations montre que vous êtes investi dans un bon codage, mais évitez d'essayer de tamponner une règle générique dans ces situations et de comprendre la raison de quelque chose à jeter en premier lieu et ce que vous pouvez faire pour s'en remettre.


6

Je sais que c'est une vieille question, mais personne ici n'a mentionné l'article MSDN, et c'est le document qui l'a réellement éclairci pour moi, MSDN a un très bon document à ce sujet, vous devriez intercepter des exceptions lorsque les conditions suivantes sont remplies:

  • Vous comprenez bien pourquoi l'exception peut être levée et vous pouvez implémenter une récupération spécifique, par exemple en invitant l'utilisateur à entrer un nouveau nom de fichier lorsque vous interceptez un objet FileNotFoundException.

  • Vous pouvez créer et lever une nouvelle exception plus spécifique.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Vous souhaitez gérer partiellement une exception avant de la transmettre pour une gestion supplémentaire. Dans l'exemple suivant, un bloc catch est utilisé pour ajouter une entrée à un journal des erreurs avant de relancer l'exception.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Je suggère de lire l'intégralité de la section " Exceptions et gestion des exceptions " ainsi que les meilleures pratiques pour les exceptions .


1

La meilleure approche est la seconde (celle dans laquelle vous spécifiez le type d'exception). L'avantage de ceci est que vous savez que ce type d'exception peut se produire dans votre code. Vous gérez ce type d'exception et vous pouvez reprendre. Si une autre exception survient, cela signifie que quelque chose ne va pas, ce qui vous aidera à trouver des bogues dans votre code. L'application finira par planter, mais vous saurez qu'il y a quelque chose que vous avez manqué (bug) qui doit être corrigé.


1

Avec des exceptions, j'essaye ce qui suit:

Tout d'abord, j'attrape des types spéciaux d'exceptions comme la division par zéro, les opérations d'E / S, etc. et j'écris du code en conséquence. Par exemple, une division par zéro, en fonction de la provenance des valeurs, je pourrais alerter l'utilisateur (par exemple une simple calculatrice en ce que dans un calcul intermédiaire (pas les arguments) arrive dans une division par zéro) ou pour traiter silencieusement cette exception, la journalisation et continuer le traitement.

Ensuite, j'essaie d'attraper les exceptions restantes et de les enregistrer. Si possible, autorisez l'exécution de code, sinon prévenez l'utilisateur qu'une erreur s'est produite et demandez-lui d'envoyer un rapport d'erreur.

Dans le code, quelque chose comme ceci:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}

1
Divisez par zéro exceptions et similaires sont mieux traités en vérifiant au 0préalable un numérateur plutôt qu'un a try-catch. Aussi pourquoi attraper le générique Exceptionici? Vous feriez mieux de laisser l'erreur bouillonner que de la traiter ici dans tous les cas où vous ne vous y attendez pas.
Keith

Lisez mieux ce que j'ai écrit sur l'exemple que j'ai donné - notez le "pas dans les arguments". Bien sûr, toute calculatrice doit vérifier les arguments donnés. J'ai parlé des étapes intermédiaires. À ce stade, la vérification de l'argument utilisateur s'est déjà produite. De plus, dans certaines applications, il est préférable d'éviter les exceptions de bulle. Certaines applications doivent traiter les exceptions en mode silencieux, tandis que d'autres doivent traiter les exceptions comme des erreurs. Un serveur Web, par exemple, devrait fonctionner même lorsque des exceptions se produisent, alors que les logiciels médicaux (machines à rayons X par exemple) devraient abandonner lorsque des exceptions se produisent.
Sorcerer86pt

Aucune application ne doit jamais traiter les exceptions en silence. Parfois, vous avez une exception que le code peut gérer, mais une telle utilisation doit être à la fois rare et spécifique à l'exception attendue. Votre exemple de serveur Web est médiocre - il devrait avoir des paramètres de configuration qui vous permettent de choisir comment les erreurs sont enregistrées et si elles sont affichées en détail ou simplement une page HTTP 500, mais elles ne doivent jamais ignorer les erreurs en silence.
Keith

J'essaie de comprendre ce qui motive vraiment les gens à ajouter encore un synonyme de "goto". Mais en ce qui concerne la division par zéro, ce serait le seul type d'exception que je puisse voir qui justifie l'amélioration du langage. Pourquoi? Parce qu'il se peut bien que A) zéro soit statistiquement un infinitésimal dans votre ensemble de données, et B) en utilisant (autorisant) une exception peut être beaucoup plus efficace, car effectuer la division est une façon de tester un diviseur nul. Lorsque A et B sont vrais, l'exécution moyenne de votre programme sera plus rapide en utilisant une exception, et elle pourrait même être plus petite.
Mike Layton

1

La deuxième approche est bonne.

Si vous ne souhaitez pas afficher l'erreur et confondre l'utilisateur de l'application en affichant une exception d'exécution (c'est-à-dire une erreur) qui ne lui est pas liée, enregistrez simplement l'erreur et l'équipe technique peut rechercher le problème et le résoudre.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Je vous recommande d'opter pour la deuxième approche pour l'ensemble de votre application.


2
La deuxième approche ne montre pas à l'utilisateur qu'une erreur s'est produite - par exemple, s'il sauvegardait quelque chose, il ne saurait pas qu'il a échoué. catchles blocs doivent toujours soit appeler la throwbulle de l'exception, soit renvoyer quelque chose / afficher quelque chose qui indique à l'utilisateur que l'action a échoué. Vous voulez obtenir l'appel d'assistance lorsqu'ils ne parviennent pas à enregistrer quoi que ce soit, pas 6 mois plus tard lorsqu'ils essaient de le récupérer et ne le trouvent pas.
Keith

0

Laisser un bloc de capture vide est la pire chose à faire. S'il y a une erreur, la meilleure façon de la gérer est de:

  1. Connectez-le dans le fichier \ base de données, etc.
  2. Essayez de le réparer à la volée (peut-être en essayant une autre façon de faire cette opération)
  3. Si nous ne pouvons pas résoudre ce problème, informez l'utilisateur qu'il y a une erreur et bien sûr abandonnez l'opération

0

Pour moi, la gestion des exceptions peut être considérée comme une règle commerciale. De toute évidence, la première approche est inacceptable. Le second est meilleur et il pourrait être 100% correct SI le contexte le dit. Maintenant, par exemple, vous développez un complément Outlook. Si vous ajoutez une exception non gérée, l'utilisateur Outlook peut maintenant le savoir car Outlook ne se détruit pas en raison de l'échec d'un plug-in. Et vous avez du mal à comprendre ce qui a mal tourné. Par conséquent, la deuxième approche dans ce cas, pour moi, c'est une approche correcte. En plus de consigner l'exception, vous pouvez décider d'afficher un message d'erreur à l'utilisateur - je le considère comme une règle métier.


0

La meilleure pratique consiste à lever une exception lorsque l'erreur se produit. Parce qu'une erreur s'est produite et ne doit pas être cachée.

Mais dans la vraie vie, vous pouvez avoir plusieurs situations lorsque vous voulez cacher cela

  1. Vous comptez sur un composant tiers et vous souhaitez continuer le programme en cas d'erreur.
  2. Vous avez une analyse de rentabilisation que vous devez continuer en cas d'erreur

6
Non . Ne pas jeter Exception. Déjà. Jetez une sous-classe appropriée de Exceptiontout ce que vous voulez, mais jamais Exceptionparce que cela ne donne absolument aucune information sémantique. Je ne peux pas voir un scénario où il est logique de lancer, Exceptionmais pas une sous-classe de celui-ci.
un CVn du


0

Le catchsans aucun argument est simplement de manger l'exception et ne sert à rien. Et si une erreur fatale se produit? Il n'y a aucun moyen de savoir ce qui s'est passé si vous utilisez catch sans argument.

Une déclaration catch doit intercepter des exceptions plus spécifiques comme FileNotFoundException, puis à la fin, vous devez intercepter Exceptionce qui intercepterait toute autre exception et les enregistrer.


Pourquoi avoir un général catch(Exception)à la fin? Si vous ne vous y attendez pas, il est toujours préférable de le transmettre à la couche suivante.
Keith

1
@ Keith oui vous avez raison ... il n'y a aucun intérêt à intercepter des exceptions auxquelles vous ne vous attendez pas, mais vous pouvez l'exception générale à des fins de journalisation ..
Anirudha

0

Parfois, vous devez traiter les exceptions qui ne disent rien aux utilisateurs.

Ma façon est:

  • Pour intercepter les exceptions non capturées au niveau de l'application (c'est-à-dire dans global.asax) pour les exceptions critiques (l'application ne peut pas être utile). Ces exemptions, je ne les attrape pas. Connectez-vous simplement au niveau de l'application et laissez le système faire son travail.
  • Attrapez "sur place" et montrez quelques informations utiles à l'utilisateur (mauvais numéro entré, impossible d'analyser).
  • Attrapez sur place et ne faites rien sur des problèmes marginaux comme "Je vais vérifier les informations de mise à jour en arrière-plan, mais le service ne fonctionne pas".

Cela ne doit certainement pas être la meilleure pratique. ;-)


0

Je peux te dire quelque chose:

L'extrait n ° 1 n'est pas acceptable, car il ignore l'exception. (c'est l'avaler comme si de rien n'était).

N'ajoutez donc pas de bloc catch qui ne fait rien ou qui rejette simplement.

Le bloc de capture devrait ajouter de la valeur. Par exemple, message de sortie à l'utilisateur final ou erreur de journal.

N'utilisez pas d'exception pour la logique de programme de flux normal. Par exemple:

par exemple, validation d'entrée. <- Ce n'est pas une situation exceptionnelle valable, vous devriez plutôt écrire la méthodeIsValid(myInput); pour vérifier si l'élément d'entrée est valide ou non.

Concevez un code pour éviter les exceptions. Par exemple:

int Parse(string input);

Si nous transmettons une valeur qui ne peut pas être analysée à int, cette méthode lèverait une exception, au lieu de cela, nous pourrions écrire quelque chose comme ceci:

bool TryParse(string input,out int result); <- cette méthode retournerait un booléen indiquant si l'analyse était réussie.

C'est peut-être un peu hors de portée de cette question, mais j'espère que cela vous aidera à prendre les bonnes décisions quand il s'agit try {} catch(){}et les exceptions.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.