Ich habe die folgende Funktion, um Validierungsfehler für eine Karte zu erhalten. Meine Frage bezieht sich auf den Umgang mit GetErrors. Beide Methoden haben den gleichen Rückgabetyp 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
}
Ist es möglich, alle Fehler zurückzugeben, GetMoreErrors
ohne sie aufzählen zu müssen?
Darüber nachzudenken ist wahrscheinlich eine dumme Frage, aber ich möchte sicherstellen, dass ich nichts falsch mache.
c#
ienumerable
yield
yield-return
John Oxley
quelle
quelle
GetCardProductionValidationErrorsFor
?Antworten:
Es ist definitiv keine dumme Frage, und es ist etwas, das F #
yield!
für eine ganze Sammlung im Vergleichyield
zu einem einzelnen Artikel unterstützt. (Das kann sehr nützlich sein in Bezug auf die Schwanzrekursion ...)Leider wird es in C # nicht unterstützt.
Wenn Sie jedoch mehrere Methoden haben, die jeweils eine zurückgeben
IEnumerable<ErrorInfo>
, können SieEnumerable.Concat
Ihren Code vereinfachen:Es gibt jedoch einen sehr wichtigen Unterschied zwischen den beiden Implementierungen: Diese ruft alle Methoden sofort auf , obwohl nur die zurückgegebenen Iteratoren einzeln verwendet werden. Ihr vorhandener Code wartet, bis er alles durchlaufen hat,
GetMoreErrors()
bevor er überhaupt nach den nächsten Fehlern fragt .Normalerweise ist dies nicht wichtig, aber es lohnt sich zu verstehen, was wann passieren wird.
quelle
GetOtherErrors()
(usw.) verschieben sie ihre Ergebnisse (da sie mithilfe von Iteratorblöcken implementiert werden). Versuchen Sie, sie zu ändern, um ein neues Array oder ähnliches zurückzugeben, und Sie werden sehen, was ich meine.Sie können alle Fehlerquellen wie folgt einrichten (Methodennamen aus Jon Skeets Antwort).
Sie können sie dann gleichzeitig durchlaufen.
Alternativ können Sie die Fehlerquellen mit reduzieren
SelectMany
.Die Ausführung der Methoden in
GetErrorSources
wird ebenfalls verzögert.quelle
Ich habe mir einen kurzen
yield_
Ausschnitt ausgedacht:Hier ist das XML-Snippet:
quelle
yield!
, wie in F #.Ich sehe nichts falsches an Ihrer Funktion, ich würde sagen, dass sie tut, was Sie wollen.
Stellen Sie sich die Ausbeute so vor, dass sie bei jedem Aufruf ein Element in der endgültigen Aufzählung zurückgibt. Wenn Sie es also so in der foreach-Schleife haben, gibt es bei jedem Aufruf 1 Element zurück. Sie haben die Möglichkeit, bedingte Anweisungen in Ihr foreach einzufügen, um die Ergebnismenge zu filtern. (einfach indem Sie Ihre Ausschlusskriterien nicht erfüllen)
Wenn Sie später in der Methode nachfolgende Ausbeuten hinzufügen, wird der Aufzählung weiterhin 1 Element hinzugefügt, sodass Sie beispielsweise ...
quelle
Ich bin überrascht, dass niemand daran gedacht hat, eine einfache Erweiterungsmethode zu empfehlen
IEnumerable<IEnumerable<T>>
, damit dieser Code seine verzögerte Ausführung beibehält. Ich bin aus vielen Gründen ein Fan von verzögerter Ausführung. Einer davon ist, dass der Speicherbedarf selbst für sehr viele Aufzählungen gering ist.Und Sie könnten es in Ihrem Fall so verwenden
Ebenso können Sie die Wrapper-Funktion aufheben
DoGetErrors
und einfachUnWrap
zur Call-Site wechseln.quelle
DoGetErrors(card).SelectMany(x => x)
sie dasselbe tut und das verzögerte Verhalten beibehält. Welches ist genau das, was Adam in seiner Antwort vorschlägt .Ja, es ist möglich, alle Fehler auf einmal zurückzugeben. Geben Sie einfach ein
List<T>
oder zurückReadOnlyCollection<T>
.Wenn
IEnumerable<T>
Sie ein zurückgeben, geben Sie eine Folge von etwas zurück. An der Oberfläche scheint dies identisch mit der Rücksendung der Sammlung zu sein, aber es gibt eine Reihe von Unterschieden, die Sie berücksichtigen sollten.Sammlungen
Sequenzen
IEnumerable<T>
ermöglicht eine verzögerte Auswertung, das ZurückgebenList<T>
nicht).quelle