Wie Sie einen Enumerator entwerfen, die (theoretisch) eine unendliche Menge an Elementen zurückgibt?

StackOverflow https://stackoverflow.com/questions/197297

  •  10-07-2019
  •  | 
  •  

Frage

Ich schreibe Code, der in etwa so aussieht:

public IEnumerable<T> Unfold<T>(this T seed)
{
    while (true)
    {
        yield return [next (T)object in custom sequence];
    }
}

Offensichtlich ist diese Methode nie wieder zurückkehren würde. (Die C # Compiler ermöglicht es leise dies, während R # gibt mir die Warnung "Funktion nie wieder" ).

Im Allgemeinen ist es schlecht Design einen Enumerator zu schaffen, die eine unendliche Anzahl von Elementen zurückgibt, ohne einen Weg zu liefern zu stoppen aufzählt?

Gibt es spezielle Überlegungen für dieses Szenario? Mem? Perf? Andere gotchas

Wenn wir immer einen Exit-Zustand liefern, die sind die Optionen? Z. B:

  • ein Objekt vom Typ T, der die inklusive oder exklusive Grenze
  • steht
  • a Predicate<T> continue (wie TakeWhile der Fall ist)
  • eine Zählung (wie Take der Fall ist)
  • ...

Sollten wir vertrauen auf den Aufruf Take(...) / TakeWhile(...) nach Unfold(...)? (Vielleicht ist die bevorzugte Option, da sie nutzt bestehendes Linq Wissen.)

Möchten Sie diese Frage anders beantworten, wenn der Code in einer öffentlichen API veröffentlicht werden würde, entweder wie sie ist (Generika) oder als spezifische Implementierung dieses Musters?

War es hilfreich?

Lösung

So lange, wie Sie ganz klar dokumentieren, dass die Methode nie fertig Iterieren (die Methode selbst kehrt sehr schnell, natürlich) dann denke ich, es ist in Ordnung. Tatsächlich kann es einige Algorithmen viel sauberer machen. Ich glaube nicht, dass es irgendwelche signifikanten Speicher / perf Auswirkungen -. Obwohl, wenn Sie zu einem „teuren“ Objekt in Ihrem Iterator beziehen, wird diese Bezugnahme aufgenommen werden

Es gibt immer Möglichkeiten des Missbrauchs APIs: so lange wie Ihre Dokumente sind klar, ich denke, es ist in Ordnung

.

Andere Tipps

  

"Allgemein gesprochen ist es schlecht Desing   einen Enumerator zu schaffen, die zurückgibt   eine unendliche Menge von Gegenständen, ohne   eine Art und Weise liefern zu stoppen aufzählt? "

Der Verbraucher des Codes, kann immer stoppen Aufzählen (mit Pause zum Beispiel oder mit anderen Mitteln). Wenn Ihr Enumerator zurück und unendliche Folge, die nicht den Client des Enumerators bedeuten irgendwie gezwungen, nie Aufzählung zu brechen, eigentlich kann man nicht einen Enumerator machen, die garantiert wird vollständig von einem Client aufgezählt werden.

  

Sollten wir vertrauen auf den Aufruf   Nehmen Sie (...) / Takewhile (...) nach   Entfalten(...)? (Vielleicht ist die bevorzugte   Option, da sie nutzt bestehende   Linq Wissen).

Ja, solange Sie eindeutig in der Dokumentation angeben, dass der Enumerator zurück und unendliche Folge und Brechen der Aufzählung in der Verantwortung des Anrufers ist, sollte alles in Ordnung sein.

unendliche Folgen Rückkehr ist keine schlechte Idee, funktionalen Programmiersprachen haben es für eine lange Zeit getan.

Ich stimme mit Jon. Compiler wandelt Ihre Methode zur Klasse Implementierung einfache Zustandsmaschine, den Bezug auf aktuellen Wert hält (das heißt Wert, der über aktuelle Eigenschaft zurückgegeben wird). Ich habe diesen Ansatz mehrmals Code zu vereinfachen. Wenn Sie klar Methode das Verhalten dokumentieren sollte es gut funktionieren.

Ich würde nicht eine unendliche Enumerator in einer öffentlichen API verwenden. C # Programmierer, mich eingeschlossen, sind auch auf der foreach-Schleife verwendet. Dies würde auch mit dem .NET Framework konsistent sein; bemerken, wie die Enumerable.Range und Enumerable.Repeat Methoden ein Argument der Anzahl der Elemente in der Enumerable zu begrenzen. Microsoft entschied sich Enumerable.Repeat ( „‚ 10) statt Enumerable.Repeat (‘“) .Nehmen (10) zu verwenden, die unendliche Aufzählung zu vermeiden, und ich würde auf ihre Design-Entscheidungen halten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top