Kann mir jemand IEnumerable und IEnumerator erklären? [geschlossen]


272

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?


54
Dies ist die schlimmste Namensverwechslung seit Java und JavaScript
Matthew Lock

@MatthewLock kannst du erklären was du meinst?
David Klempfner

Antworten:


274

Zum Beispiel, wann es über foreach verwendet werden soll?

Sie verwenden nicht IEnumerable"over" foreach. Implementierung IEnumerablemacht Verwendung foreach möglich .

Wenn Sie Code schreiben wie:

foreach (Foo bar in baz)
{
   ...
}

es ist funktional gleichbedeutend mit Schreiben:

IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
   bar = (Foo)bat.Current
   ...
}

Mit "funktional äquivalent" meine ich, dass der Compiler den Code tatsächlich so umwandelt. Sie können nicht foreachauf die bazin diesem Beispiel , es sei denn baz implementiert IEnumerable.

IEnumerablebedeutet, dass bazdie Methode implementiert

IEnumerator GetEnumerator()

Das von IEnumeratordieser Methode zurückgegebene Objekt muss die Methoden implementieren

bool MoveNext()

und

Object Current()

Die erste Methode fährt mit dem nächsten Objekt in dem IEnumerableObjekt fort, das den Enumerator erstellt hat, und gibt zurück, falsewenn 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 erbt IEnumerable, können Sie Ihre Klasse in foreachAnweisungen verwenden, indem Sie sie implementieren IEnumerable(und eine Enumerator-Klasse erstellen, die von ihrer neuen GetEnumeratorMethode zurückgegeben wird).


15
Ich denke, als auf dem Originalposter "over foreach" stand, meinte er "wann sollte ich GetEnumerator () / MoveNext () explizit aufrufen, anstatt eine foreach-Schleife zu verwenden." Für was es wert ist.
mqp

6
Ah, ich denke du hast recht. Nun, die Antwort ist in meinem Beitrag implizit enthalten: Es spielt keine Rolle, da der Compiler dies sowieso tut. Tun Sie also, was am einfachsten ist, dh verwenden Sie foreach.
Robert Rossney

12
Diese Antwort erzählt nicht die ganze Geschichte. Aufzählbare Objekte müssen IEnumerable nicht implementieren. Sie benötigen lediglich eine GetEnumerator-Methode, die eine Instanz eines Typs zurückgibt, der wiederum eine bool MoveNext()Methode und eine CurrentEigenschaft 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.
Phoog

3
Mit der Erklärung von oben und dem Durcharbeiten von Workthrough: Implementieren von IEnumerable of (T) haben Sie großartige Quellen.
Ruedi

4
Ist das wie ein C ++ iterator?
Matt G

161

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:

// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
   Console.WriteLine(i);
}

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:

// Garage contains a set of Car objects.
public class Garage
{
   private Car[] carArray = new Car[4];
   // Fill with some Car objects upon startup.
   public Garage()
   {
      carArray[0] = new Car("Rusty", 30);
      carArray[1] = new Car("Clunker", 55);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
}

Im Idealfall ist es praktisch, die Unterelemente des Garage-Objekts mithilfe des foreach-Konstrukts zu durchlaufen, genau wie bei einem Array von Datenwerten:

// This seems reasonable ...
public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
      Garage carLot = new Garage();
      // Hand over each car in the collection?
      foreach (Car c in carLot)
      {
         Console.WriteLine("{0} is going {1} MPH",
         c.PetName, c.CurrentSpeed);
      }
      Console.ReadLine();
   }
}

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:

// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
   IEnumerator GetEnumerator();
}

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:

// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
   bool MoveNext (); // Advance the internal position of the cursor.
   object Current { get;} // Get the current item (read-only property).
   void Reset (); // Reset the cursor before the first member.
}

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:

using System.Collections;
...
public class Garage : IEnumerable
{
   // System.Array already implements IEnumerator!
   private Car[] carArray = new Car[4];
   public Garage()
   {
      carArray[0] = new Car("FeeFee", 200);
      carArray[1] = new Car("Clunker", 90);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
   public IEnumerator GetEnumerator()
   {
      // Return the array object's IEnumerator.
      return carArray.GetEnumerator();
   }
}

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:

// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);

Wenn Sie jedoch die Funktionalität von IEnumerable auf Objektebene ausblenden möchten, verwenden Sie einfach die explizite Schnittstellenimplementierung:

IEnumerator IEnumerable.GetEnumerator()
{
  // Return the array object's IEnumerator.
  return carArray.GetEnumerator();
}

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


1
Fantastische Antwort, danke! Ich habe allerdings eine Frage. Im ersten Beispiel durchlaufen Sie das Array mit foreach, im zweiten Beispiel jedoch nicht. Liegt das daran, dass sich das Array in einer Klasse befindet oder dass es Objekte enthält?
Caleb Palmquist

Vielen Dank für die tolle Erklärung. Meine einzige Frage ist , warum nicht nur eine Methode in Garagedas bekommt carArray? Auf diese Weise müssen Sie sich nicht selbst implementieren GetEnumerator, da dies Arraybereits geschieht. ZBforeach(Car c in carLot.getCars()) { ... }
Nick Rolando

62

Das Implementieren von IEnumerable bedeutet, dass Ihre Klasse ein IEnumerator-Objekt zurückgibt:

public class People : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        // return a PeopleEnumerator
    }
}

Wenn Sie IEnumerator implementieren, gibt Ihre Klasse die Methoden und Eigenschaften für die Iteration zurück:

public class PeopleEnumerator : IEnumerator
{
    public void Reset()...

    public bool MoveNext()...

    public object Current...
}

Das ist sowieso der Unterschied.


1
Schön, dies erklärt (zusammen mit den anderen Beiträgen), wie Sie Ihre Klasse in eine Klasse konvertieren können, auf der Sie "foreach" verwenden können, um den Inhalt zu durchlaufen.
Contango

54

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:

  1. zählbar und
  2. wenn es einen Zähler hat.

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:

  1. Der Schalter / Flugbegleiter MUSS vor dem ersten Passagier starten (vor jedem, wo er die Sicherheit demonstriert, wie er die Schwimmweste anzieht usw.).
  2. Er / sie (dh der Flugbegleiter) MUSS "weiter" den Gang hinauf zum ersten Sitzplatz gehen.
  3. Er / sie muss dann aufzeichnen: (i) wer die Person auf dem Sitz ist und (ii) ihren aktuellen Standort im Gang.

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.

  • Der Schalter läuft weiter, bis er das Ende des Flugzeugs erreicht.

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!)

    foreach (Passenger passenger in Plane)
    // the airline hostess is now at the front of the plane
    // and slowly making her way towards the back
    // when she get to a particular passenger she gets some information
    // about the passenger and then immediately heads to the cabin
    // to let the captain decide what to do with it
    { // <---------- Note the curly bracket that is here.
        // we are now cockpit of the plane with the captain.
        // the captain wants to give the passenger free 
        // champaign if they support manchester city
        if (passenger.supports_mancestercity())
        {
            passenger.getFreeChampaign();
        } else
        {
            // you get nothing! GOOD DAY SIR!
        }
    } //  <---- Note the curly bracket that is here!
          the hostess has delivered the information 
          to the captain and goes to the next person
          on the plane (if she has not reached the 
          end of the plane)

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).


23

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.


18

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.


Wenn es sich um eine Liste handelt, warum kann ich dann nicht einfach foreach verwenden?
Prodev42

.Net duck gibt die foreach-Anweisung ein, aber IEnumerable / IEnumerable <T> ist die geeignete Methode, um zu sagen, dass Ihre Klasse aufgezählt werden kann.
user7116

15
  • Ein Objekt, das IEnumerable implementiert, ermöglicht es anderen, jedes seiner Elemente (durch einen Enumerator) zu besuchen .
  • Ein Objekt, das IEnumerator implementiert, ist die Iteration. Es durchläuft ein aufzählbares Objekt.

Stellen Sie sich unzählige Objekte wie Listen, Stapel, Bäume vor.


12

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

foreach (var value in list)
  Console.WriteLine(value);

Ich denke, foreachSchleife ist einer der Hauptgründe für die Verwendung von IEnumerable- Schnittstellen. foreachhat 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 returnund yield breakAnweisungen aktiviert .

IEnumerable<Thing> GetThings() {
   if (isNotReady) yield break;
   while (thereIsMore)
     yield return GetOneMoreThing();
}

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.

var iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

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 foreachSchleife bereitstellt, obwohl hinter den Kulissen Daten unter Verwendung verschiedener Dateistreams und Serialisierungen gesammelt wurden.

Client-Code

foreach(var item in feed.GetItems())
    Console.WriteLine(item);

Bibliothek

IEnumerable GetItems() {
    return new FeedIterator(_fileNames)
}

class FeedIterator: IEnumerable {
    IEnumerator GetEnumerator() {
        return new FeedExplicitIterator(_stream);
    }
}

class FeedExplicitIterator: IEnumerator {
    DataItem _current;

    bool MoveNext() {
        _current = ReadMoreFromStream();
        return _current != null;           
    }

    DataItem Current() {
        return _current;   
    }
}

9

Das Implementieren IEnumerablebedeutet 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.

IEnumeratorist 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& IEnumeratortransparent als Teil einer foreachSchleife verwendet.


6

Unterschiede zwischen IEnumerable und IEnumerator:

  • IEnumerable verwendet IEnumerator intern.
  • IEnumerable weiß nicht, welches Element / Objekt ausgeführt wird.
  • Immer wenn wir IEnumerator an eine andere Funktion übergeben, kennt er die aktuelle Position von Element / Objekt.
  • 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 ()

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> 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).

public interface IEnumerator
{
     object Current { get; }
     bool MoveNext();
     void Reset();
}

5

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.

public class Customer
{
    public String Name { get; set; }
    public String City { get; set; }
    public long Mobile { get; set; }
    public double Amount { get; set; }
}

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.

public class CustomerList : IEnumerable
{
    Customer[] customers = new Customer[4];
    public CustomerList()
    {
        customers[0] = new Customer { Name = "Bijay Thapa", City = "LA", Mobile = 9841639665, Amount = 89.45 };
        customers[1] = new Customer { Name = "Jack", City = "NYC", Mobile = 9175869002, Amount = 426.00 };
        customers[2] = new Customer { Name = "Anil min", City = "Kathmandu", Mobile = 9173694005, Amount = 5896.20 };
        customers[3] = new Customer { Name = "Jim sin", City = "Delhi", Mobile = 64214556002, Amount = 596.20 };
    }

    public int Count()
    {
        return customers.Count();
    }
    public Customer this[int index]
    {
        get
        {
            return customers[index];
        }
    }
    public IEnumerator GetEnumerator()
    {
        return customers.GetEnumerator(); // we can do this but we are going to make our own Enumerator
        return new CustomerEnumerator(this);
    }
}

Jetzt erstellen wir unseren eigenen benutzerdefinierten Enumerator wie folgt. Also müssen wir die Methode MoveNext implementieren.

 public class CustomerEnumerator : IEnumerator
    {
        CustomerList coll;
        Customer CurrentCustomer;
        int currentIndex;
        public CustomerEnumerator(CustomerList customerList)
        {
            coll = customerList;
            currentIndex = -1;
        }

        public object Current => CurrentCustomer;

        public bool MoveNext()
        {
            if ((currentIndex++) >= coll.Count() - 1)
                return false;
            else
                CurrentCustomer = coll[currentIndex];
            return true;
        }

        public void Reset()
        {
            // we dont have to implement this method.
        }
    }

Jetzt können wir foreach Schleife über unsere Sammlung wie unten verwenden;

    class EnumeratorExample
    {
        static void Main(String[] args)
        {

            CustomerList custList = new CustomerList();
            foreach (Customer cust in custList)
            {
                Console.WriteLine("Customer Name:"+cust.Name + " City Name:" + cust.City + " Mobile Number:" + cust.Amount);
            }
            Console.Read();

        }
    }

4

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 Iteratormuster

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.

 int count = 0;
        var permutations = perm.getPermutations(inputString);
        foreach (string permutation in permutations)
        {
            count++;
        }

Der c # -Compiler konvertiert das Obige mehr oder weniger in

using (var permutationIterator = perm.getPermutations(input).GetEnumerator())
        {
            while (permutationIterator.MoveNext())
            {
                count++;
            }
        }

Wenn Sie Fragen haben, zögern Sie bitte nicht zu fragen.


2

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.

static void EnumerableVsEnumeratorStateTest()
{
    IList<int> numList = new List<int>();

    numList.Add(1);
    numList.Add(2);
    numList.Add(3);
    numList.Add(4);
    numList.Add(5);
    numList.Add(6);

    Console.WriteLine("Using Enumerator - Remembers the state");
    IterateFrom1to3(numList.GetEnumerator());

    Console.WriteLine("Using Enumerable - Does not Remembers the state");
    IterateFrom1to3Eb(numList);

    Console.WriteLine("Using Enumerable - 2nd functions start from the item 1 in the collection");
}

static void IterateFrom1to3(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());

        if (numColl.Current > 3)
        {
            // This method called 3 times for 3 items (4,5,6) in the collection. 
            // It remembers the state and displays the continued values.
            IterateFrom3to6(numColl);
        }
    }
}

static void IterateFrom3to6(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());
    }
}

static void IterateFrom1to3Eb(IEnumerable<int> numColl)
{
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());

        if (num>= 5)
        {
            // The below method invokes for the last 2 items.
            //Since it doesnot persists the state it will displays entire collection 2 times.
            IterateFrom3to6Eb(numColl);
        }
    }
}

static void IterateFrom3to6Eb(IEnumerable<int> numColl)
{
    Console.WriteLine();
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());
    }
}

2

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


1

IEnumerableund IEnumeratorbeide sind Schnittstellen in C #.

IEnumerableist eine Schnittstelle, die eine einzelne Methode definiert GetEnumerator(), die eine IEnumeratorSchnittstelle zurückgibt .

Dies funktioniert für den schreibgeschützten Zugriff auf eine Sammlung, die implementiert, IEnumerabledie mit einer foreachAnweisung verwendet werden kann.

IEnumeratorhat zwei Methoden, MoveNextund Reset. Es hat auch eine Eigenschaft namens Current.

Das Folgende zeigt die Implementierung von IEnumerable und IEnumerator.


0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enudemo
{

    class Person
    {
        string name = "";
        int roll;

        public Person(string name, int roll)
        {
            this.name = name;
            this.roll = roll;
        }

        public override string ToString()
        {
            return string.Format("Name : " + name + "\t Roll : " + roll);
        }

    }


    class Demo : IEnumerable
    {
        ArrayList list1 = new ArrayList();

        public Demo()
        {
            list1.Add(new Person("Shahriar", 332));
            list1.Add(new Person("Sujon", 333));
            list1.Add(new Person("Sumona", 334));
            list1.Add(new Person("Shakil", 335));
            list1.Add(new Person("Shruti", 336));
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
           return list1.GetEnumerator();
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();  // Notice here. it is simple object but for 
                                //IEnumerator you can get the collection data

            foreach (Person X in d)
            {
                Console.WriteLine(X);
            }

            Console.ReadKey();
        }
    }
}
/*
Output : 

Name : Shahriar  Roll : 332
Name : Sujon     Roll : 333
Name : Sumona    Roll : 334
Name : Shakil    Roll : 335
Name : Shruti    Roll : 336
  */
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.