J'ai la fonction suivante pour obtenir des erreurs de validation pour une carte. Ma question concerne le traitement de GetErrors. Les deux méthodes ont le même type de retour IEnumerable<ErrorInfo>
.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
var errors = GetMoreErrors(card);
foreach (var e in errors)
yield return e;
// further yield returns for more validation errors
}
Est-il possible de renvoyer toutes les erreurs dans GetMoreErrors
sans avoir à les énumérer?
Penser à cela est probablement une question stupide, mais je veux m'assurer de ne pas me tromper.
c#
ienumerable
yield
yield-return
John Oxley
la source
la source
GetCardProductionValidationErrorsFor
?Réponses:
Ce n'est certainement pas une question stupide, et c'est quelque chose que F # prend en charge
yield!
pour une collection entière par rapportyield
à un seul élément. (Cela peut être très utile en termes de récursion de queue ...)Malheureusement, il n'est pas pris en charge en C #.
Cependant, si vous avez plusieurs méthodes retournant chacune un
IEnumerable<ErrorInfo>
, vous pouvez utiliserEnumerable.Concat
pour simplifier votre code:Il y a cependant une différence très importante entre les deux implémentations: celle-ci appellera toutes les méthodes immédiatement , même si elle n'utilisera les itérateurs renvoyés qu'un par un. Votre code existant attendra d'être bouclé sur tout ce qu'il contient
GetMoreErrors()
avant même de poser des questions sur les prochaines erreurs.Généralement, ce n'est pas important, mais cela vaut la peine de comprendre ce qui va se passer quand.
la source
GetOtherErrors()
(etc.) reportent leurs résultats (car ils sont implémentés à l'aide de blocs d'itérateur). Essayez de les changer pour renvoyer un nouveau tableau ou quelque chose comme ça, et vous verrez ce que je veux dire.Vous pouvez configurer toutes les sources d'erreur comme celle-ci (noms de méthodes empruntés à la réponse de Jon Skeet).
Vous pouvez ensuite les parcourir en même temps.
Vous pouvez également aplatir les sources d'erreur avec
SelectMany
.L'exécution des méthodes en
GetErrorSources
sera également retardée.la source
Je suis venu avec un
yield_
extrait rapide :Voici l'extrait de code XML:
la source
yield!
, comme en F #.Je ne vois rien de mal à votre fonction, je dirais qu'elle fait ce que vous voulez.
Considérez le rendement comme renvoyant un élément dans l'énumération finale chaque fois qu'il est appelé, donc quand vous l'avez dans la boucle foreach comme ça, chaque fois qu'il est appelé, il renvoie 1 élément. Vous avez la possibilité de mettre des instructions conditionnelles dans votre foreach pour filtrer l'ensemble de résultats. (simplement en ne cédant pas à vos critères d'exclusion)
Si vous ajoutez des rendements ultérieurs plus tard dans la méthode, elle continuera à ajouter 1 élément à l'énumération, ce qui permet de faire des choses comme ...
la source
Je suis surpris que personne n'ait pensé à recommander une méthode d'extension simple
IEnumerable<IEnumerable<T>>
pour que ce code conserve son exécution différée. Je suis un fan de l'exécution différée pour de nombreuses raisons, l'une d'elles est que l'empreinte mémoire est faible, même pour des énumérables énormes.Et tu pourrais l'utiliser dans ton cas comme ça
De même, vous pouvez supprimer la fonction wrapper
DoGetErrors
et vous déplacer simplementUnWrap
vers le site d'appel.la source
DoGetErrors(card).SelectMany(x => x)
fait de même et préserve le comportement différé. C'est exactement ce qu'Adam suggère dans sa réponse .Oui, il est possible de renvoyer toutes les erreurs à la fois. Renvoyez simplement un
List<T>
ouReadOnlyCollection<T>
.En retournant un,
IEnumerable<T>
vous retournez une séquence de quelque chose. En apparence, cela peut sembler identique au retour de la collection, mais il y a un certain nombre de différences, vous devez garder à l'esprit.Les collections
Séquences
IEnumerable<T>
permet une évaluation paresseuse, le retourList<T>
ne le permet pas).la source