IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Accumuler plusieurs exceptions de même type


Sujet :

C#

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Médecin
    Inscrit en
    Mai 2019
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Médecin
    Secteur : Santé

    Informations forums :
    Inscription : Mai 2019
    Messages : 8
    Points : 5
    Points
    5
    Par défaut Accumuler plusieurs exceptions de même type
    Salut à tous !

    J'ai un programme de la forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    protected int GetValueOne()
    {
        if (DetectSomethingWrong()) throw new PersonnalizedException();
        return CalculateSomething();
    }
     
    protected int GetValueTwo()
    {
        if (DetectSomethingWrong()) throw new PersonnalizedException();
        return CalculateSomething();
    }
     
    public double GetFinalValue()
    {
        try
        {
            return GetValueOne() / GetValueTwo();
        }
        catch (PersonnalizedException exception)
        {
            CallTHisMethodWhenAnExceptionHasBeenCatched(exception);
            throw;
        }
    }
    En fait, mon exception PersonnalizedException correspond dans mon cas à exception contenant un message et une suite de valeurs nécessaires pour CalculateSomething(), dont la vérification a échoué (ex : pas remplies par l'utilisateur). Afin de faciliter la vie de mon utilisateur, je souhaite que le message puisse afficher l'ensemble des valeurs non remplies, afin qu'il ne commette pas 2 fois la même erreur.

    Pour l'instant j'ai envisagé de remplacer la gestion de ces exceptions par la mise à jour d'une liste de valeurs "non remplies" (contenue dans une propriété de type List). Si cette liste n'est pas vide au moment de l'appel à GetFinalValue(), cela lance une PersonnalizedException qui contient donc le même message, mais avec une liste complète des valeurs car la liste est fournie en paramètre au constructeur de la classe PersonnalizedException.

    Mais cela ne me convient pas tout à fait pour plusieurs raisons :
    1. L'exception n'est pas gérée de façon "propre" : je préfère générer une exception au sein de chaque méthode, ce qui m'évite de me poser la question de "comment chaque exception est gérée au sein de chaque méthode ?" et pouvoir simplement les catcher quand les dites méthodes sont appelées
    2. Je ne souhaite pas modifier la logique de mes méthodes GetValueOne() et GetValueTwo(), qui retournent soit le résultat d'un calcul, soit génèrent une exception en cas d'échec (là encore, c'est beaucoup plus propre) ; je ne souhaite pas retourner une valeur random en cas d'échec du calcul
    3. J'ai déjà une propriété contenant une exception qui me permet de la communiquer à ma vue pour le respect du modèle MVVM, et je trouve que c'est déjà un peu limite ; je ne souhaite donc pas pourrir mon code avec une nouvelle propriété (la liste des valeurs non remplies) qui nécessite à nouveau un système de vérification / reset.


    J'ai aussi pensé à générer une liste des exceptions dans ma propriété de type Exception, mais cela ne règle pas mon problème actuel : seule la 1ère exception est lancée et donc catchée...

    Des idées ? Ou est-ce que je me plante complètement et que les exceptions ne sont pas faites pour gérer les erreurs d'entrée de l'utilisateur ?...

  2. #2
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    C'est une question intéressante. Une exception est faite pour interrompre le flux normal d'un programme dès lors qu'un problème survient. Ici, il s'agit d'accumuler les exceptions avant d'en déclencher une. Ce n'est clairement pas le principe de base d'une exception.

    Mais on peut tout de même arriver à quelque chose d'approchant en rusant un peu, et en utilisant des Task tout en gardant vos différentes contraintes. Cela va par contre demander une réécriture de la méthode GetFinalValue.

    Voici une idée de code (non testé) :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    public double GetFinalValue()
    {
        try
        {
            int valueOne;
            int valueTwo;
            List<Task> tasks = new List<Task>();
     
            tasks.Add(Task.Run(() => valueOne = GetValueOne());
            tasks.Add(Task.Run(() => valueTwo = GetValueTwo());
            Task.WaitAll(tasks);
     
            //si ce code est atteint, toutes les tâches se sont exécutées correctement, on peut continuer
            return valueOne / valueTwo
        }
        catch (AggregateException exception)
        {
            // Une erreur s'est produite lors de la récupération d'au moins une valeur.
            // exception.InnerExceptions contient la liste des exceptions qui ont été générées.
            // On peut en faire ce que l'on veut ensuite, en extraire les informations utiles et 
            // générer une nouvelle exception par exemple.
            CallTHisMethodWhenAnExceptionHasBeenCatched(exception);
            throw;
        }
    }

    Enfin, il est tout à fait possible de rajouter une propriété à votre exception contenant l'ensemble des champs ayant une erreur. Ou de créer une nouvelle exception. Ainsi, cela vous évite de rajouter une propriété à votre vue.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Médecin
    Inscrit en
    Mai 2019
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Médecin
    Secteur : Santé

    Informations forums :
    Inscription : Mai 2019
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Bonjour,

    Merci pour cette approche intéressante. Je ne comprends pas bien ce que les Task changent au déroulement du programme, mais je vais me pencher sur la doc. En tout cas pour le moment c'est la meilleure option que j'aie vu, merci !

    J'ai pensé à une autre façon de faire, sur laquelle je voudrais bien un avis : l'idée pour moi était de ne pas briser la logique de mon code (l'appel au modèle suppose que le VM a déjà fait les vérifications d'usage ; mon modèle ne consiste donc qu'en un accès "pur" à des formules de calcul, qui ne nécessitent aucune vérification). D'où les exceptions générées dans le VM, au sein de chaque méthode, et pas dans une seule méthode qui engloberait toute la logique (pour laquelle d'ailleurs je n'aurais pas la possibilité d'utiliser le bloc try...catch... mais seulement throw). Mon idée suivante marche, mais je ne sais pas si c'est "correct" et logique : est-ce que je ne peux pas utiliser l'IHM, donc la view, pour faire ces vérifications d'usage ?

    En d'autres termes, ajouter un niveau de vérification en faisant checker par la view ses propres champs (au sens entrée utilisateur, pas au sens champs de classe), et conserver mon système d'exception dans le VM pour que soit gérée, au cas où, une erreur qui n'aurait pas été gérée par la vue.

    Ça paraît censé comme façon de faire ? Ou est-ce que la vue n'est pas du tout censée opérer ce genre de vérifications ?

  4. #4
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par galactose Voir le message
    Merci pour cette approche intéressante. Je ne comprends pas bien ce que les Task changent au déroulement du programme, mais je vais me pencher sur la doc. En tout cas pour le moment c'est la meilleure option que j'aie vu, merci !
    C'est vrai que je n'ai pas beaucoup donné d'explication. Ma réponse était un peu tardive pendant que je m'occupais d'une grosse mise à jour. Donc détails supplémentaires sur l'explication.

    Une Task permet ici d'introduire du parallélisme. Le code de la Task sera exécuté sur un thread différent. Ici, l'idée est donc de récupérer les différentes informations requises dans des Task différents, et d'attendre (via le Task.WaitAll) que l'ensemble des tâches ont correctement été exécutées.

    L'astuce est que quand une exception est générée dans une tâche, l'exception n'est levée qu'au moment où on interragit avec la tâche (par exemple, en récupérant son résultat ou en attendant la fin de son exécution). C'est exactement ce que fait ici Task.WaitAll, sauf qu'il attend sur un ensemble de tâche et non pas une seule, et qu'il génère une exception AggragateException avec l'ensemble des exceptions générées lorsque cela s'avère nécessaire.


    Citation Envoyé par galactose Voir le message
    J'ai pensé à une autre façon de faire, sur laquelle je voudrais bien un avis : l'idée pour moi était de ne pas briser la logique de mon code (l'appel au modèle suppose que le VM a déjà fait les vérifications d'usage ; mon modèle ne consiste donc qu'en un accès "pur" à des formules de calcul, qui ne nécessitent aucune vérification). D'où les exceptions générées dans le VM, au sein de chaque méthode, et pas dans une seule méthode qui engloberait toute la logique (pour laquelle d'ailleurs je n'aurais pas la possibilité d'utiliser le bloc try...catch... mais seulement throw). Mon idée suivante marche, mais je ne sais pas si c'est "correct" et logique : est-ce que je ne peux pas utiliser l'IHM, donc la view, pour faire ces vérifications d'usage ?

    En d'autres termes, ajouter un niveau de vérification en faisant checker par la view ses propres champs (au sens entrée utilisateur, pas au sens champs de classe), et conserver mon système d'exception dans le VM pour que soit gérée, au cas où, une erreur qui n'aurait pas été gérée par la vue.

    Ça paraît censé comme façon de faire ? Ou est-ce que la vue n'est pas du tout censée opérer ce genre de vérifications ?
    Oui tout à fait. En général, tant que les vérifications sont sur la forme (format attendu, par exemple, un nombre et pas du text, présence d'un champ obligatoire, etc...) cela ne pose aucun problème de mettre des vérifications au sein de la vue et ne casse en rien la séparation vue/modèle.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Médecin
    Inscrit en
    Mai 2019
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Médecin
    Secteur : Santé

    Informations forums :
    Inscription : Mai 2019
    Messages : 8
    Points : 5
    Points
    5
    Par défaut
    Très bien, alors merci encore pour cette réponse sur les Task (qui a l'air de marcher parfaitement !), et merci pour la réponse à ma question plus théorique car je pense désormais opter pour cette solution en implémentant un visual state manager dans mes vues XAML, tout en conservant mon système d'exceptions "actuel" dans mes VM qui me permettra de garantir une certaine "sécurité" dans la logique de mon code si je change de vue un jour.

  6. #6
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Juste histoire d'être complet, il est possible de faire la même chose sans les tasks. Mais c'est très lourd à écrire, car il faut faire chaque accès à une méthode comme GetValueOne ou GetValueTwo dans un try/catch, et ajouter les exceptions dans une liste si jamais elles surviennent.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 30/07/2009, 19h46
  2. Comment Créer plusieurs constructeur de même type ?
    Par mobi_bil dans le forum Débuter avec Java
    Réponses: 6
    Dernier message: 29/07/2009, 13h35
  3. Réponses: 1
    Dernier message: 07/10/2008, 15h49
  4. Réponses: 18
    Dernier message: 21/09/2006, 11h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo