Würde C # profitiert von Unterscheidungen zwischen Arten von Aufzählungen, wie C ++ Iteratoren?

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

  •  06-07-2019
  •  | 
  •  

Frage

Ich habe über die IEnumerator.Reset() Methode nachgedacht. Ich las in der MSDN-Dokumentation, dass es dort nur für COM-Interop. Als C ++ Programmierer für mich ist es wie ein IEnumerator sieht die Reset unterstützt ist, was würde ich ein vorwärts-Iterator , während ein IEnumerator die nicht Reset unterstützt ist wirklich ein InputIterator .

So Teil einer meiner Frage ist, ist dieses Verständnis richtig?

Der zweite Teil meiner Frage ist, wäre es von Nutzen in C #, wenn es ein Unterschied zwischen dem Eingang Iteratoren und vorwärts Iteratoren (oder „Aufzählungen“, wenn Sie bevorzugen) gemacht wird? Wäre es nicht helfen, einige Verwirrung unter den Programmierern zu beseitigen, wie die in diesem SO Frage zu klonen Iteratoren gefunden ?

EDIT: Klarstellung nach vorn und Eingang Iteratoren. Ein InputIterator garantiert nur, dass Sie die Mitglieder einer Sammlung nur einmal aufzählen können (oder von einer Generatorfunktion oder einem Eingangsstrom). Das ist genau, wie IEnumerator arbeitet in C #. Unabhängig davon, ob Sie ein zweites Mal aufzählen, wird dadurch bestimmt, ob oder ob nicht Reset unterstützt wird. Ein Forward-Iterator, diese Einschränkung nicht hat. Sie können die Mitglieder aufzählen über so oft wie Sie wollen.

Einige C # Programmierer underestand nicht, warum ein IEnumerator nicht zuverlässig in einem Mehrweg-Algorithmus verwendet werden. Betrachten Sie den folgenden Fall:

void PrintContents(IEnumerator<int> xs)
{
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
  iter.Reset();
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
}

Wenn wir PrintContents in diesem Zusammenhang nennen, kein Problem:

List<int> ys = new List<int>() { 1, 2, 3 }
PrintContents(ys.GetEnumerator()); 

Allerdings Blick auf die folgenden:

IEnumerable<int> GenerateInts() {   
  System.Random rnd = new System.Random();
  for (int i=0; i < 10; ++i)
    yield return Rnd.Next();
}

PrintContents(GenerateInts());

Wenn die IEnumerator unterstützt Reset, mit anderen Worten Multi-Pass-Algorithmen unterstützt, dann wird jedes Mal, wenn Sie über die Kollektion iteriert wäre es anders sein. Dies wäre nicht wünschenswert, weil es überraschende Verhalten wäre. Dieses Beispiel ist ein wenig gefälscht, aber es funktioniert in der realen Welt auftritt (zum Beispiel von Datei-Streams zu lesen).

War es hilfreich?

Lösung

Interessante Frage. Meine Meinung ist, dass natürlich C # würde Nutzen . Allerdings wäre es nicht einfach sein, hinzuzufügen.

Der Unterschied besteht in C ++ wegen seiner viel flexibler Typ-System. In C # müssen Sie nicht auf eine robuste generische Art und Weise Objekte zu klonen, die Vorwärts-Iteratoren, die erforderlich ist (Multi-Pass-Iteration zu unterstützen). Und natürlich für diese wirklich nützlich sein, dann würden Sie auch bidirektional und Random-Access-Iteratoren / Aufzählungen unterstützen müssen. Und um sie alle reibungslos funktioniert, müssen Sie wirklich eine Form von Ente-Typisierung, wie C ++ Vorlagen haben.

Letztlich sind die Bereiche der beiden Konzepte unterschiedlich.

In C ++ Iteratoren soll alles, was man über einen Bereich von Werten wissen müssen, darzustellen. ein Paar von Iteratoren gegeben, ich weiß nicht Notwendigkeit , um den Originalbehälter. Ich kann sortieren, ich suche, kann ich manipulieren und Elemente so viel kopieren, wie Ich mag. Der Originalbehälter ist aus dem Bild heraus.

In C #, Aufzählungen sind nicht zu tun, ganz so viel bedeutet. Letztlich sind sie nur entworfen, um Sie durch die Sequenz in einer linearen Weise laufen zu lassen.

Wie bei Reset() ist es allgemein anerkannt, dass es ein Fehler war es in erster Linie hinzuzufügen. Wenn es gearbeitet hatte, und korrekt durchgeführt, dann ja, könnte man sagen, Ihr enumerator wurde analog Iteratoren zu übermitteln, aber im Allgemeinen ist es am besten, es als ein Fehler zu ignorieren. Und dann werden alle Aufzählungen sind ähnlich nur zur Eingabe von Iteratoren.

Leider.

Andere Tipps

Reset war ein großer Fehler. Ich nenne Shenanigans auf Reset. Meiner Meinung nach ist der richtige Weg, um den Unterschied Sie machen zwischen „Vorwärts-Iteratoren“ und „Eingabe-Iteratoren“ in .NET-Typ-System zu reflektieren ist mit der Unterscheidung zwischen IEnumerable<T> und IEnumerator<T>.

Siehe diese Antwort , wo Eric Lippert von Microsoft (in einer inoffiziellen capactiy, kein Zweifel, mein Punkt ist nur, dass er jemand mit mehr Anmeldeinformationen als ich den Anspruch zu machen, dass dies ein Fehler war, Design) macht einen ähnlichen Punkt in den Kommentaren. Siehe auch auch sein ehrfürchtiger Blog .

Von der C # Perspektive:

Sie verwenden fast nie IEnumerator direkt. Normalerweise haben Sie eine foreach Anweisung, die eine IEnumerable erwartet.

IEnumerable _myCollection;
...
foreach (var item in _myCollection) { /* Do something */ }

Sie gehen nicht um entweder IEnumerator. Wenn Sie eine Sammlung übergeben, die Iteration benötigt, übergeben Sie IEnumerable. Da IEnumerable eine einzige Funktion, die eine IEnumerator zurückgibt, kann es die Sammlung mehrere Male (mehrere Durchgänge).

iterieren verwendet werden

Es gibt keine Notwendigkeit für eine Reset() Funktion auf IEnumerator denn wenn Sie von vorne beginnen möchten, müssen Sie nur die alte wegzuwerfen (Garbage Collection) und ein neues erhalten.

Der .NET-Framework würde enorm profitieren, wenn es ein Mittel ist ein IEnumerator<T> fragen, über welche Fähigkeiten könnte es unterstützen und was verspricht, könnte es machen. Solche Merkmale auch in IEnumerable<T> hilfreich sein würden, aber die Fragen einer enumerator zu stellen in der Lage, Code erlauben würde, die einen Enumerator von Umhüllungen wie ReadOnlyCollection empfangen können die zugrunde liegende Sammlung zu verbessern Möglichkeiten zu nutzen, ohne die Hülle zu beteiligen zu haben.

Bei jedem Enumerator für eine Sammlung, die infolge die aufgezählten in seiner Gesamtheit fähig ist und nicht zu groß ist, könnte man daraus ein IEnumerable<T> erzeugen, die die gleiche Sequenz von Elementen immer ergeben würden (insbesondere die Menge des Artikels noch in der Enumerator) mit seinem gesamten Inhalt auf ein Array zu lesen, und die Entsorgung Enumerator Verwerfen, und erhalte eine Aufzählungskonstanten aus dem Array (unter Verwendung daß anstelle des ursprünglichen aufgegeben Enumerator), wobei die Anordnung in einem ReadOnlyCollection<T> Einwickeln und zurückkehren das. Obwohl ein solcher Ansatz mit jeder Art von aufzählbare Auflistung, welche den oben genannten Kriterien funktionieren würde, wäre es mit den meisten von ihnen schrecklich ineffizient sein. ein Mittel, zu fragen einen Enumerator, dessen restliche Inhalt in einer unveränderlichen IEnumerable<T> liefern viele Arten von Aufzählungen erlauben würde, die angegebene Aktion wesentlich effizienter durchzuführen.

Das glaube ich nicht so. Ich würde nennen IEnumerable einen Vorwärts-Iterator und einen InputIterator. Es erlaubt Ihnen nicht, rückwärts zu gehen, oder die zugrunde liegende Auflistung ändern. Mit der Zugabe des foreach Schlüsselwort, sind Iteratoren fast ein Nicht-Denken die meiste Zeit.

Stellungnahme: Die Differenz zwischen Eingang Iteratoren ( jeder bekommen ) vs. Ausgabe Iteratoren ( etwas tun, um jeden ) ist zu trivial eine Ergänzung zu dem Rahmen zu rechtfertigen. Auch, um ein Output-Iterator zu tun, müßten Sie einen Delegaten Iterator zu übergeben. Der InputIterator scheint natürlicher zu C # -Programmierer.

Es gibt auch IList<T>, wenn der Programmierer random access will.

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