Lors de l'analyse des entrées utilisateur, il est généralement recommandé de ne pas lever et intercepter les exceptions mais plutôt d'utiliser des méthodes de validation. Dans le .NET BCL, ce serait la différence entre, par exemple, int.Parse
(lève une exception sur les données non valides) et int.TryParse
(renvoie false
sur les données non valides).
Je conçois le mien
Foo.TryParse(string s, out Foo result)
et je ne suis pas sûr de la valeur de retour. Je pourrais utiliser bool
comme la propre TryParse
méthode de .NET , mais cela ne donnerait aucune indication sur le type d'erreur, sur la raison exacte pour laquelle il s
n'a pas pu être analysé dans un Foo
. (Par exemple, s
pourrait avoir des parenthèses sans correspondance, ou le mauvais nombre de caractères, ou un Bar
sans correspondant Baz
, etc.)
En tant qu'utilisateur d'API, je n'aime pas du tout les méthodes qui renvoient simplement un succès / échec booléen sans me dire pourquoi l'opération a échoué. Cela fait du débogage un jeu de devinettes, et je ne veux pas non plus imposer cela aux clients de ma bibliothèque.
Je peux penser à de nombreuses solutions de contournement à ce problème (renvoyer les codes d'état, renvoyer une chaîne d'erreur, ajouter une chaîne d'erreur comme paramètre de sortie), mais ils ont tous leurs inconvénients respectifs, et je veux également rester cohérent avec les conventions de le .NET Framework .
Ainsi, ma question est la suivante:
Existe-t-il des méthodes dans le .NET Framework qui (a) analysent les entrées sans lever d'exceptions et (b) renvoient toujours des informations d'erreur plus détaillées qu'un simple booléen vrai / faux?
la source
Parse()
.Réponses:
Je recommanderais d'utiliser le modèle de monade pour votre type de retour.
ParseResult<Foo> foo = FooParser.Parse("input");
Notez également qu'il ne devrait pas être de la responsabilité de Foo de comprendre comment il doit être analysé à partir des entrées utilisateur, car cela lie directement votre couche de domaine à votre couche d'interface utilisateur et viole également le principal de responsabilité unique.
Vous pouvez également créer une classe de résultats d'analyse spécifique à
Foo
au lieu d'utiliser des génériques, selon votre cas d'utilisation.Une classe de résultat d'analyse spécifique à foo pourrait ressembler à ceci:
Voici la version Monad:
Je ne connais aucune méthode dans le framework .net qui renvoie des informations détaillées sur les erreurs d'analyse.
la source
Foo.ToString
etFoo.Parse
.Func<T>
répondrait à ces critères, si vous incluezT
les informations dont vous avez besoin. Le retour d'informations détaillées sur les erreurs vous appartient en grande partie. Avez-vous pensé à utiliser unMaybe<T>
? Voir mikhail.io/2016/01/monads-explained-in-csharpVous pouvez regarder ModelState dans le framework MVC. Il représente une tentative d'analyse de certaines entrées et peut contenir une collection d'erreurs.
Cela dit, je ne pense pas qu'il existe un modèle récurrent dans le BCL .net, car les exceptions sont - pour le meilleur ou pour le pire - le modèle établi pour signaler les conditions d'erreur dans le .net. Je pense que vous devriez simplement aller de l'avant et implémenter votre propre solution adaptée à votre problème, par exemple une
ParseResult
classe avec deux sous-classes,SuccessfulParse
etFailedParse
, oùSuccessfulParse
a une propriété avec la valeur analysée etFailedParse
a une propriété de message d'erreur. Combiner cela avec la correspondance de motifs en C # 7 pourrait être assez élégant.la source
J'ai rencontré des problèmes similaires en voulant utiliser une
TryParse/Convert/etc.
méthode où j'ai parfois besoin de savoir comment et pourquoi elle a échoué.J'ai fini par m'inspirer de la façon dont certains sérialiseurs gèrent les erreurs et utilisent les événements. De cette façon, la syntaxe de ma
TryX(..., out T)
méthode semble aussi propre que n'importe quelle autre et renvoie de manière fiable un simplefalse
comme le modèle l'indique.Cependant, lorsque je veux avoir plus de détails, j'ajoute simplement un gestionnaire d'événements et j'obtiens les résultats dont j'ai besoin dans un package aussi complexe ou simple que je le souhaite (
MyEventArgs
ci - dessous). Ajoutez-le à une liste de chaînes, ajoutez uneExceptionDispatchInfo
et capturez les exceptions; laissez l'appelant décider si et comment il veut faire face à tout ce qui ne va pas.la source