Kann mir jemand IEnumerable und IEnumerator erklären?
Zum Beispiel, wann es über foreach verwendet werden soll? Was ist der Unterschied zwischen IEnumerable und IEnumerator? Warum müssen wir es benutzen?
c#
ienumerable
ienumerator
prodev42
quelle
quelle
Antworten:
Sie verwenden nicht
IEnumerable
"over"foreach
. ImplementierungIEnumerable
macht Verwendungforeach
möglich .Wenn Sie Code schreiben wie:
es ist funktional gleichbedeutend mit Schreiben:
Mit "funktional äquivalent" meine ich, dass der Compiler den Code tatsächlich so umwandelt. Sie können nicht
foreach
auf diebaz
in diesem Beispiel , es sei dennbaz
implementiertIEnumerable
.IEnumerable
bedeutet, dassbaz
die Methode implementiertDas von
IEnumerator
dieser Methode zurückgegebene Objekt muss die Methoden implementierenund
Die erste Methode fährt mit dem nächsten Objekt in dem
IEnumerable
Objekt fort, das den Enumerator erstellt hat, und gibt zurück,false
wenn dies erledigt ist, und die zweite Methode gibt das aktuelle Objekt zurück.Alles in .Net, was Sie über Geräte iterieren können
IEnumerable
. Wenn Sie eine eigene Klasse erstellen und diese noch nicht von einer implementierten Klasse erbtIEnumerable
, können Sie Ihre Klasse inforeach
Anweisungen verwenden, indem Sie sie implementierenIEnumerable
(und eine Enumerator-Klasse erstellen, die von ihrer neuenGetEnumerator
Methode zurückgegeben wird).quelle
bool MoveNext()
Methode und eineCurrent
Eigenschaft eines beliebigen Typs enthält. Dieser Ansatz der "Ententypisierung" wurde in C # 1.0 implementiert, um das Boxen bei der Aufzählung von Werttypsammlungen zu vermeiden.iterator
?Die Schnittstellen IEnumerable und IEnumerator
Um den Prozess der Implementierung vorhandener .NET-Schnittstellen zu untersuchen, betrachten wir zunächst die Rolle von IEnumerable und IEnumerator. Denken Sie daran, dass C # ein Schlüsselwort mit dem Namen foreach unterstützt, mit dem Sie den Inhalt eines beliebigen Array-Typs durchlaufen können:
Während es den Anschein haben mag, dass nur Array-Typen dieses Konstrukt verwenden können, ist die Wahrheit, dass jeder Typ, der eine Methode namens GetEnumerator () unterstützt, vom foreach-Konstrukt ausgewertet werden kann. Um dies zu veranschaulichen, folgen Sie mir!
Angenommen, wir haben eine Garage-Klasse:
Im Idealfall ist es praktisch, die Unterelemente des Garage-Objekts mithilfe des foreach-Konstrukts zu durchlaufen, genau wie bei einem Array von Datenwerten:
Leider informiert Sie der Compiler darüber, dass die Garage-Klasse keine Methode namens GetEnumerator () implementiert. Diese Methode wird durch die IEnumerable-Schnittstelle formalisiert, die sich im System.Collections-Namespace befindet. Klassen oder Strukturen, die dieses Verhalten unterstützen, geben an, dass sie enthaltene Unterelemente für den Aufrufer verfügbar machen können (in diesem Beispiel das Schlüsselwort foreach selbst). Hier ist die Definition dieser Standard-.NET-Schnittstelle:
Wie Sie sehen können, gibt die GetEnumerator () -Methode einen Verweis auf eine weitere Schnittstelle mit dem Namen System.Collections.IEnumerator zurück. Diese Schnittstelle bietet die Infrastruktur, mit der der Aufrufer die im IEnumerable-kompatiblen Container enthaltenen internen Objekte durchlaufen kann:
Wenn Sie den Garagentyp aktualisieren möchten, um diese Schnittstellen zu unterstützen, können Sie den langen Weg gehen und jede Methode manuell implementieren. Es steht Ihnen sicherlich frei, benutzerdefinierte Versionen von GetEnumerator (), MoveNext (), Current und Reset () bereitzustellen. Es gibt jedoch einen einfacheren Weg. Da der System.Array-Typ (sowie viele andere Auflistungsklassen) bereits IEnumerable und IEnumerator implementiert, können Sie die Anforderung einfach wie folgt an System.Array delegieren:
Nachdem Sie Ihren Garagentyp aktualisiert haben, können Sie den Typ sicher im C # foreach-Konstrukt verwenden. Da die GetEnumerator () -Methode öffentlich definiert wurde, kann der Objektbenutzer außerdem mit dem IEnumerator-Typ interagieren:
Wenn Sie jedoch die Funktionalität von IEnumerable auf Objektebene ausblenden möchten, verwenden Sie einfach die explizite Schnittstellenimplementierung:
Auf diese Weise findet der Benutzer eines zufälligen Objekts die GetEnumerator () -Methode von Garage nicht, während das foreach-Konstrukt die Schnittstelle bei Bedarf im Hintergrund abruft.
Angepasst an Pro C # 5.0 und .NET 4.5 Framework
quelle
Garage
das bekommtcarArray
? Auf diese Weise müssen Sie sich nicht selbst implementierenGetEnumerator
, da diesArray
bereits geschieht. ZBforeach(Car c in carLot.getCars()) { ... }
Das Implementieren von IEnumerable bedeutet, dass Ihre Klasse ein IEnumerator-Objekt zurückgibt:
Wenn Sie IEnumerator implementieren, gibt Ihre Klasse die Methoden und Eigenschaften für die Iteration zurück:
Das ist sowieso der Unterschied.
quelle
Erklärung über Analogy + Code Walkthrough
Zuerst eine Erklärung ohne Code, dann werde ich sie später hinzufügen.
Angenommen, Sie leiten eine Fluggesellschaft. Und in jedem Flugzeug möchten Sie Informationen über die Passagiere erhalten, die im Flugzeug fliegen. Grundsätzlich möchten Sie in der Lage sein, das Flugzeug zu "durchqueren". Mit anderen Worten, Sie möchten in der Lage sein, auf dem Vordersitz zu beginnen und sich dann nach hinten zu arbeiten und die Passagiere nach Informationen zu fragen: Wer sie sind, woher sie kommen usw. Ein Flugzeug kann dies nur , wenn es ist:
Warum diese Anforderungen? Denn genau das benötigt die Schnittstelle.
Wenn dies eine Informationsüberflutung ist, müssen Sie lediglich wissen, dass Sie jedem Passagier im Flugzeug einige Fragen stellen möchten, angefangen von der ersten bis zur letzten.
Was bedeutet zählbar?
Wenn eine Fluggesellschaft "zählbar" ist, bedeutet dies, dass ein Flugbegleiter im Flugzeug anwesend sein MUSS, dessen einzige Aufgabe es ist, zu zählen - und dieser Flugbegleiter MUSS auf ganz bestimmte Weise zählen:
Zählverfahren
Der Kapitän der Fluggesellschaft möchte einen Bericht über jeden Passagier, wenn dieser untersucht oder gezählt wird. Nachdem der Flugbegleiter / Schalter mit der Person auf dem ersten Platz gesprochen hat, meldet er sich beim Kapitän. Wenn der Bericht vorliegt, merkt sich der Schalter seine genaue Position im Gang und zählt weiter genau dort, wo er abgereist ist aus.
Auf diese Weise kann der Kapitän immer Informationen über die aktuell untersuchte Person erhalten. Auf diese Weise kann er, wenn er herausfindet, dass diese Person Manchester City mag, dem Passagier eine Vorzugsbehandlung usw. gewähren.
Lassen Sie uns dies mit den IEnumerables verknüpfen
Eine Aufzählung ist nur eine Ansammlung von Passagieren in einem Flugzeug. Das Zivilluftfahrtgesetz - dies sind im Grunde die Regeln, denen alle IEnumerables folgen müssen. Jedes Mal, wenn der Flugbegleiter mit den Passanteninformationen zum Kapitän geht, geben wir den Passagier im Grunde genommen dem Kapitän ab. Der Kapitän kann grundsätzlich mit dem Passagier machen, was er will - außer die Passagiere im Flugzeug neu zu ordnen. In diesem Fall werden sie bevorzugt behandelt, wenn sie Manchester City folgen (ugh!)
Zusammenfassung
Mit anderen Worten, etwas ist zählbar, wenn es einen Zähler hat . Und der Zähler muss (im Grunde): (i) sich an seinen Platz ( Zustand ) erinnern , (ii) sich als nächstes bewegen können , (iii) und über die aktuelle Person Bescheid wissen, mit der er es zu tun hat.
Aufzählbar ist nur ein schickes Wort für "zählbar". Mit anderen Worten, eine Aufzählung ermöglicht es Ihnen, "aufzuzählen" (dh zu zählen).
quelle
IEnumerable implementiert GetEnumerator. Beim Aufruf gibt diese Methode einen IEnumerator zurück, der MoveNext, Reset und Current implementiert.
Wenn Ihre Klasse IEnumerable implementiert, sagen Sie, dass Sie eine Methode (GetEnumerator) aufrufen und ein neues Objekt zurückgeben können (einen IEnumerator), das Sie in einer Schleife wie foreach verwenden können.
quelle
Durch die Implementierung von IEnumerable können Sie einen IEnumerator für eine Liste abrufen.
IEnumerator ermöglicht jedem Stil sequentiellen Zugriff auf die Elemente in der Liste unter Verwendung des Schlüsselworts yield.
Vor jeder Implementierung (z. B. in Java 1.4) bestand die Möglichkeit, eine Liste zu iterieren, darin, einen Enumerator aus der Liste abzurufen und ihn dann nach dem "nächsten" Element in der Liste zu fragen, solange der Wert als nächster zurückgegeben wird Artikel ist nicht null. Foreach tut dies einfach implizit als Sprachfunktion, genauso wie lock () die Monitor-Klasse hinter den Kulissen implementiert.
Ich erwarte, dass foreach auf Listen arbeitet, weil sie IEnumerable implementieren.
quelle
Stellen Sie sich unzählige Objekte wie Listen, Stapel, Bäume vor.
quelle
IEnumerable und IEnumerator (und ihre generischen Gegenstücke IEnumerable <T> und IEnumerator <T>) sind Basisschnittstellen für Iterator- Implementierungen in .Net Framework Class Libray-Sammlungen .
IEnumerable ist die häufigste Schnittstelle, die Sie im Großteil des Codes sehen würden. Es aktiviert die foreach-Schleife, Generatoren (Think Yield ) und wird aufgrund seiner winzigen Schnittstelle verwendet, um enge Abstraktionen zu erstellen. IEnumerable hängt vom IEnumerator ab .
IEnumerator bietet dagegen eine etwas niedrigere Iterationsschnittstelle. Es wird als expliziter Iterator bezeichnet, der dem Programmierer mehr Kontrolle über den Iterationszyklus gibt.
IEnumerable
IEnumerable ist eine Standardschnittstelle, die das Iterieren über Sammlungen ermöglicht, die dies unterstützen (tatsächlich implementieren alle Sammlungstypen, an die ich heute denken kann, IEnumerable ). Die Compiler-Unterstützung ermöglicht Sprachfunktionen wie
foreach
. Im Allgemeinen ermöglicht es diese implizite Iterator-Implementierung .foreach Schleife
Ich denke,
foreach
Schleife ist einer der Hauptgründe für die Verwendung von IEnumerable- Schnittstellen.foreach
hat eine sehr prägnante Syntax und ist im Vergleich zum klassischen C- Stil für Schleifen, bei denen Sie die verschiedenen Variablen überprüfen müssen, um zu sehen, was sie taten, sehr einfach zu verstehen .Ausbeute Schlüsselwort
Wahrscheinlich ist eine weniger bekannte Funktion, dass IEnumerable auch Generatoren in C # mit der Verwendung von
yield return
undyield break
Anweisungen aktiviert .Abstraktionen
Ein weiteres in der Praxis übliches Szenario ist die Verwendung von IEnumerable , um minimalistische Abstraktionen bereitzustellen. Da es sich um eine winzige und schreibgeschützte Oberfläche handelt, sollten Sie Ihre Sammlungen als IEnumerable (und nicht als List ) anzeigen . Auf diese Weise können Sie Ihre Implementierung ändern, ohne den Code Ihres Kunden zu beschädigen (ändern Sie beispielsweise die Liste in eine LinkedList ).
Erwischt
Beachten Sie, dass Sie bei Streaming-Implementierungen (z. B. zeilenweises Abrufen von Daten aus einer Datenbank, anstatt zuerst alle Ergebnisse in den Speicher zu laden) die Sammlung nicht mehr als einmal durchlaufen können . Dies steht im Gegensatz zu In-Memory-Sammlungen wie List , bei denen Sie problemlos mehrere Male iterieren können. ReSharper verfügt beispielsweise über eine Codeüberprüfung für die mögliche mehrfache Aufzählung von IEnumerable .
IEnumerator
IEnumerator hingegen ist die Schnittstelle hinter den Kulissen, über die IEnumerble-foreach-magic funktioniert. Genau genommen ermöglicht es explizite Iteratoren.
Nach meiner Erfahrung wird IEnumerator aufgrund seiner ausführlicheren Syntax und leicht verwirrenden Semantik in allgemeinen Szenarien selten verwendet (zumindest für mich; z. B. gibt MoveNext () ebenfalls einen Wert zurück, den der Name überhaupt nicht andeutet ).
Anwendungsfall für IEnumerator
Ich habe nur IEnumerator verwendet, insbesondere (etwas niedrigere) Bibliotheken und Frameworks, in denen ich IEnumerable- Schnittstellen bereitgestellt habe . Ein Beispiel ist eine Datenstromverarbeitungsbibliothek, die eine Reihe von Objekten in einer
foreach
Schleife bereitstellt, obwohl hinter den Kulissen Daten unter Verwendung verschiedener Dateistreams und Serialisierungen gesammelt wurden.Client-Code
Bibliothek
quelle
Das Implementieren
IEnumerable
bedeutet im Wesentlichen, dass das Objekt wiederholt werden kann. Dies bedeutet nicht unbedingt, dass es sich um ein Array handelt, da bestimmte Listen nicht indiziert werden können, Sie sie jedoch auflisten können.IEnumerator
ist das eigentliche Objekt, mit dem die Iterationen durchgeführt werden. Es steuert das Verschieben von einem Objekt zum nächsten in der Liste.Meistens werden
IEnumerable
&IEnumerator
transparent als Teil einerforeach
Schleife verwendet.quelle
Unterschiede zwischen IEnumerable und IEnumerator:
Immer wenn wir eine IEnumerable-Auflistung an eine andere Funktion übergeben, kennt sie die aktuelle Position des Elements / Objekts nicht (weiß nicht, welches Element ausgeführt wird).
IEnumerable haben eine Methode GetEnumerator ()
IEnumerator verfügt über eine Eigenschaft namens Current und zwei Methoden, Reset () und MoveNext () (nützlich, um die aktuelle Position eines Elements in einer Liste zu ermitteln).
quelle
IEnumerable ist eine Box, die Ienumerator enthält. IEnumerable ist die Basisschnittstelle für alle Sammlungen. Die foreach-Schleife kann ausgeführt werden, wenn die Sammlung IEnumerable implementiert. Im folgenden Code wird der Schritt erläutert, einen eigenen Enumerator zu haben. Definieren wir zuerst unsere Klasse, aus der wir die Sammlung machen werden.
Jetzt definieren wir die Klasse, die als Sammlung für unseren Klassenkunden dient. Beachten Sie, dass die Schnittstelle IEnumerable implementiert wird. Damit müssen wir die Methode GetEnumerator implementieren. Dies gibt unseren benutzerdefinierten Enumerator zurück.
Jetzt erstellen wir unseren eigenen benutzerdefinierten Enumerator wie folgt. Also müssen wir die Methode MoveNext implementieren.
Jetzt können wir foreach Schleife über unsere Sammlung wie unten verwenden;
quelle
Ein Verständnis des Iteratormusters ist hilfreich für Sie. Ich empfehle das gleiche zu lesen.
Iteratormuster
Auf hoher Ebene kann das Iteratormuster verwendet werden, um eine Standardmethode zum Durchlaufen von Sammlungen eines beliebigen Typs bereitzustellen. Wir haben 3 Teilnehmer im Iteratormuster, der tatsächlichen Sammlung (Client), dem Aggregator und dem Iterator. Das Aggregat ist eine Schnittstellen- / abstrakte Klasse mit einer Methode, die einen Iterator zurückgibt. Iterator ist eine Interface- / Abstract-Klasse mit Methoden, mit denen wir eine Sammlung durchlaufen können.
Um das Muster zu implementieren, müssen wir zuerst einen Iterator implementieren, um einen Beton zu erzeugen, der über die betroffene Sammlung (Client) iterieren kann. Dann implementiert die Sammlung (Client) den Aggregator, um eine Instanz des obigen Iterators zurückzugeben.
Hier ist das UML-Diagramm
Im Grunde genommen ist IEnumerable in c # das abstrakte Aggregat und IEnumerator der abstrakte Iterator. IEnumerable verfügt über eine einzelne Methode GetEnumerator, die für die Erstellung einer Instanz von IEnumerator des gewünschten Typs verantwortlich ist. Sammlungen wie Listen implementieren die IEnumerable.
Beispiel. Nehmen wir an, wir haben eine Methode
getPermutations(inputString)
, die alle Permutationen eines Strings zurückgibt, und die Methode gibt eine Instanz von zurückIEnumerable<string>
Um die Anzahl der Permutationen zu zählen, könnten wir so etwas wie das Folgende tun.
Der c # -Compiler konvertiert das Obige mehr oder weniger in
Wenn Sie Fragen haben, zögern Sie bitte nicht zu fragen.
quelle
Ein kleiner Beitrag.
Wie viele von ihnen erklären, wann sie verwendet werden sollen und wie sie mit foreach verwendet werden sollen. Ich dachte an das Hinzufügen eines weiteren Staaten Unterschied hier in Frage über den Unterschied zwischen den beiden IEnumerable ein IEnumerator angefordert.
Ich habe das folgende Codebeispiel basierend auf den folgenden Diskussionsthreads erstellt.
IEnumerable, IEnumerator vs foreach, wann was zu verwenden ist Was ist der Unterschied zwischen IEnumerator und IEnumerable?
Enumerator behält den Status (Iterationsposition) zwischen Funktionsaufrufen bei, während Iterationen Enumerable dies nicht tun.
Hier ist das getestete Beispiel mit Kommentaren zu verstehen.
Experten bitte hinzufügen / korrigieren.
quelle
Ich habe diese Unterschiede bemerkt:
A. Wir iterieren die Liste auf unterschiedliche Weise. Foreach kann für IEnumerable und while-Schleife für IEnumerator verwendet werden.
B. IEnumerator kann sich den aktuellen Index merken, wenn wir von einer Methode zur nächsten wechseln (er beginnt mit dem aktuellen Index zu arbeiten), aber IEnumerable kann sich nicht an den Index erinnern und setzt den Index auf den Anfang zurück. Mehr in diesem Video https://www.youtube.com/watch?v=jd3yUjGc9M0
quelle
IEnumerable
undIEnumerator
beide sind Schnittstellen in C #.IEnumerable
ist eine Schnittstelle, die eine einzelne Methode definiertGetEnumerator()
, die eineIEnumerator
Schnittstelle zurückgibt .Dies funktioniert für den schreibgeschützten Zugriff auf eine Sammlung, die implementiert,
IEnumerable
die mit einerforeach
Anweisung verwendet werden kann.IEnumerator
hat zwei Methoden,MoveNext
undReset
. Es hat auch eine Eigenschaft namensCurrent
.Das Folgende zeigt die Implementierung von IEnumerable und IEnumerator.
quelle
quelle