Quelqu'un peut-il m'expliquer IEnumerable et IEnumerator? [fermé]


272

Quelqu'un peut-il m'expliquer IEnumerable et IEnumerator?

par exemple, quand l'utiliser sur foreach? quelle est la différence entre IEnumerable et IEnumerator? Pourquoi devons-nous l'utiliser?


55
C'est le pire mélange de noms depuis Java et JavaScript
Matthew Lock

@MatthewLock pouvez-vous expliquer ce que vous voulez dire?
David Klempfner

Réponses:


275

par exemple, quand l'utiliser sur foreach?

Vous n'utilisez pas IEnumerable"over" foreach. L'implémentation IEnumerablerend foreach possible l' utilisation .

Lorsque vous écrivez du code comme:

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

il est fonctionnellement équivalent à l'écriture:

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

Par «fonctionnellement équivalent», je veux dire que c'est en fait ce que le compilateur transforme le code. Vous ne pouvez pas utiliser foreachsur bazdans cet exemple à moins baz que des outils IEnumerable.

IEnumerablesignifie que bazmet en œuvre la méthode

IEnumerator GetEnumerator()

L' IEnumeratorobjet renvoyé par cette méthode doit implémenter les méthodes

bool MoveNext()

et

Object Current()

La première méthode passe à l'objet suivant dans l' IEnumerableobjet qui a créé l'énumérateur, en retournant falsesi c'est fait, et la seconde retourne l'objet actuel.

Tout ce que vous pouvez parcourir en .Net sur des outils IEnumerable. Si vous créez votre propre classe, et qu'elle n'hérite pas déjà d'une classe qui implémente IEnumerable, vous pouvez rendre votre classe utilisable dans les foreachinstructions en implémentant IEnumerable(et en créant une classe énumérateur que sa nouvelle GetEnumeratorméthode retournera).


15
Je pense que lorsque l'affiche originale a dit "over foreach", il a voulu dire "quand devrais-je appeler GetEnumerator () / MoveNext () explicitement au lieu d'utiliser une boucle foreach." Pour ce que ça vaut.
mqp

6
Ah, je pense que tu as raison. Eh bien, la réponse est implicite dans mon article: cela n'a pas d'importance, car c'est ce que fait le compilateur de toute façon. Faites ce qui est le plus simple, c'est-à-dire utilisez foreach.
Robert Rossney

12
Cette réponse ne raconte pas toute l'histoire. Les objets énumérables n'ont pas besoin d'implémenter IEnumerable; ils n'ont besoin que d'une méthode GetEnumerator qui renvoie une instance d'un type qui à son tour a une bool MoveNext()méthode et une Currentpropriété de n'importe quel type. Cette approche de "typage du canard" a été implémentée en C # 1.0 comme un moyen d'éviter la boxe lors de l'énumération des collections de type valeur.
phoog

3
Avec l'exlanation ci-dessus et en passant par Workthrough: Implémentation de IEnumerable de (T), vous avez de grandes sources.
ruedi

4
Est-ce un peu comme un C ++ iterator?
Matt G

162

Les interfaces IEnumerable et IEnumerator

Pour commencer à examiner le processus de mise en œuvre des interfaces .NET existantes, examinons d'abord le rôle de IEnumerable et IEnumerator. Rappelez-vous que C # prend en charge un mot-clé nommé foreach qui vous permet d'itérer sur le contenu de tout type de tableau:

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

Bien qu'il puisse sembler que seuls les types de tableau peuvent utiliser cette construction, la vérité est que tout type prenant en charge une méthode nommée GetEnumerator () peut être évalué par la construction foreach. Pour illustrer, suivez-moi!

Supposons que nous ayons une classe Garage:

// 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);
   }
}

Idéalement, il serait pratique d'itérer sur les sous-éléments de l'objet Garage à l'aide de la construction foreach, tout comme un tableau de valeurs de données:

// 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();
   }
}

Malheureusement, le compilateur vous informe que la classe Garage n'implémente pas une méthode nommée GetEnumerator (). Cette méthode est formalisée par l'interface IEnumerable, qui se cache dans l'espace de noms System.Collections. Les classes ou les structures qui prennent en charge ce comportement annoncent qu'elles sont capables d'exposer des sous-éléments contenus à l'appelant (dans cet exemple, le mot-clé foreach lui-même). Voici la définition de cette interface .NET standard:

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

Comme vous pouvez le voir, la méthode GetEnumerator () renvoie une référence à une autre interface nommée System.Collections.IEnumerator. Cette interface fournit l'infrastructure permettant à l'appelant de parcourir les objets internes contenus par le conteneur compatible IEnumerable:

// 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.
}

Si vous souhaitez mettre à jour le type Garage pour prendre en charge ces interfaces, vous pouvez prendre le long chemin et implémenter chaque méthode manuellement. Bien que vous soyez certainement libre de fournir des versions personnalisées de GetEnumerator (), MoveNext (), Current et Reset (), il existe un moyen plus simple. Comme le type System.Array (ainsi que de nombreuses autres classes de collection) implémente déjà IEnumerable et IEnumerator, vous pouvez simplement déléguer la demande à System.Array comme suit:

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();
   }
}

Après avoir mis à jour votre type de garage, vous pouvez utiliser le type en toute sécurité dans la construction C # foreach. De plus, étant donné que la méthode GetEnumerator () a été définie publiquement, l'utilisateur de l'objet peut également interagir avec le type IEnumerator:

// 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);

Cependant, si vous préférez masquer la fonctionnalité de IEnumerable au niveau de l'objet, utilisez simplement l'implémentation d'interface explicite:

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

Ce faisant, l'utilisateur de l'objet occasionnel ne trouvera pas la méthode GetEnumerator () de Garage, tandis que la construction foreach obtiendra l'interface en arrière-plan si nécessaire.

Adapté de Pro C # 5.0 et du .NET 4.5 Framework


1
Fantastique réponse, merci! J'ai une question cependant. Dans le premier exemple, vous bouclez sur le tableau à l'aide de foreach, mais vous ne pouvez pas le faire dans le deuxième exemple. Est-ce parce que le tableau est dans une classe ou parce qu'il contient des objets?
Caleb Palmquist

Merci pour la grande explication. Ma seule question est pourquoi ne pas simplement avoir une méthode Garagequi obtient carArray? De cette façon, vous n'avez pas à GetEnumeratorvous implémenter , car Arraycela se fait déjà. Par exempleforeach(Car c in carLot.getCars()) { ... }
Nick Rolando

63

Implémenter IEnumerable signifie que votre classe retourne un objet IEnumerator:

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

L'implémentation d'IEnumerator signifie que votre classe renvoie les méthodes et les propriétés d'itération:

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

    public bool MoveNext()...

    public object Current...
}

C'est de toute façon la différence.


1
Bien, cela explique (avec les autres articles) comment convertir votre classe en une classe sur laquelle vous pouvez utiliser "foreach" pour parcourir son contenu.
Contango

54

Explication via Analogy + Code Walkthrough

D'abord une explication sans code, puis je l'ajouterai plus tard.

Disons que vous dirigez une compagnie aérienne. Et dans chaque avion, vous voulez connaître les informations sur les passagers volant dans l'avion. Fondamentalement, vous voulez pouvoir "traverser" l'avion. En d'autres termes, vous voulez pouvoir commencer au siège avant, puis avancer vers l'arrière de l'avion, en demandant aux passagers des informations: qui ils sont, d'où ils viennent, etc. Un avion ne peut que faire cela , Si c'est:

  1. dénombrable, et
  2. s'il a un compteur.

Pourquoi ces exigences? Parce que c'est ce dont l'interface a besoin.

S'il s'agit d'une surcharge d'informations, tout ce que vous devez savoir, c'est que vous voulez pouvoir poser des questions à chaque passager de l'avion, en commençant par la première et en passant par la dernière.

Que signifie dénombrable?

Si une compagnie aérienne est "dénombrable", cela signifie qu'il DOIT y avoir un agent de bord présent dans l'avion, dont le seul travail est de compter - et cet agent de bord DOIT compter de manière très spécifique:

  1. Le compteur / agent de bord DOIT commencer avant le premier passager (à l'avant de tout le monde où ils démontrent la sécurité, comment mettre le gilet de sauvetage, etc.).
  2. Il / elle (c.-à-d. L'agent de bord) DOIT «se déplacer ensuite» dans l'allée jusqu'au premier siège.
  3. Il / elle doit ensuite enregistrer: (i) qui est la personne sur le siège, et (ii) sa position actuelle dans l'allée.

Procédures de comptage

Le capitaine de la compagnie aérienne veut un rapport sur chaque passager au fur et à mesure de son enquête ou de son dénombrement. Ainsi, après avoir parlé à la personne occupant le premier siège, l'agent de bord / compteur se présente ensuite au commandant de bord, et lorsque le rapport est donné, le compteur se souvient de sa position exacte dans l'allée et continue de compter là où il / elle est parti. de.

De cette manière, le capitaine est toujours en mesure d'avoir des informations sur la personne en cours d'enquête. De cette façon, s'il découvre que cette personne aime Manchester City, il peut accorder à ce passager un traitement préférentiel, etc.

  • Le compteur continue jusqu'à ce qu'il atteigne la fin de l'avion.

Lions cela avec les IEnumerables

  • Un énumérable n'est qu'une collection de passagers dans un avion. La loi sur l'aviation civile - ce sont essentiellement les règles que tous les IEnumerables doivent suivre. Chaque fois que l'agent de bord se rend chez le capitaine avec les informations du passger, nous «cédons» essentiellement le passager au capitaine. Le capitaine peut essentiellement faire ce qu'il veut avec le passager - sauf réorganiser les passagers dans l'avion. Dans ce cas, ils bénéficient d'un traitement préférentiel s'ils suivent Manchester City (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)

Résumé

En d'autres termes, quelque chose est dénombrable s'il a un compteur . Et le compteur doit (fondamentalement): (i) se souvenir de sa place ( état ), (ii) être capable de se déplacer ensuite , (iii) et connaître la personne actuelle avec laquelle il a affaire.

Enumerable est juste un mot de fantaisie pour "dénombrable". En d'autres termes, un énumérable vous permet «d'énumérer» (c'est-à-dire de compter).


23

IEnumerable implémente GetEnumerator. Lorsqu'elle est appelée, cette méthode retourne un IEnumerator qui implémente MoveNext, Reset et Current.

Ainsi, lorsque votre classe implémente IEnumerable, vous dites que vous pouvez appeler une méthode (GetEnumerator) et obtenir un nouvel objet retourné (un IEnumerator) que vous pouvez utiliser dans une boucle telle que foreach.


18

L'implémentation d'IEnumerable vous permet d'obtenir un IEnumerator pour une liste.

IEnumerator permet un accès séquentiel de chaque style aux éléments de la liste, à l'aide du mot-clé yield.

Avant l'implémentation de foreach (dans Java 1.4, par exemple), la manière d'itérer une liste était d'obtenir un énumérateur de la liste, puis de lui demander l'élément "suivant" dans la liste, tant que la valeur renvoyée était la suivante l'élément n'est pas nul. Foreach le fait simplement implicitement en tant que fonctionnalité de langage, de la même manière que lock () implémente la classe Monitor en arrière-plan.

Je m'attends à ce que foreach fonctionne sur des listes car ils implémentent IEnumerable.


si c'est pour une liste pourquoi ne puis-je pas simplement utiliser foreach?
prodev42

.Net duck tape l'instruction foreach, mais IEnumerable / IEnumerable <T> est la façon appropriée de dire que votre classe peut être énumérée.
user7116

15
  • Un objet implémentant IEnumerable permet à d'autres de visiter chacun de ses éléments (par un énumérateur) .
  • Un objet implémentant IEnumerator fait l'itération. Il passe en boucle sur un objet énumérable.

Considérez les objets énumérables comme des listes, des piles, des arbres.


12

IEnumerable et IEnumerator (et leurs homologues génériques IEnumerable <T> et IEnumerator <T>) sont des interfaces de base des implémentations d' itérateur dans les collections Libray de la classe .Net Framework .

IEnumerable est l'interface la plus courante que vous verriez dans la majorité du code. Il active la boucle foreach, les générateurs (pensez au rendement ) et en raison de sa petite interface, il est utilisé pour créer des abstractions serrées. IEnumerable dépend de IEnumerator .

IEnumerator , en revanche, fournit une interface d'itération de niveau légèrement inférieur. Il est appelé l' itérateur explicite qui donne au programmeur plus de contrôle sur le cycle d'itération.

IEnumerable

IEnumerable est une interface standard qui permet d'itérer sur les collections qui la prennent en charge (en fait, tous les types de collections auxquels je peux penser aujourd'hui implémentent IEnumerable ). Le support du compilateur permet des fonctionnalités de langue comme foreach. D'une manière générale, il permet cette implémentation implicite d'itérateur .

boucle foreach

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

Je pense que la foreachboucle est l'une des principales raisons d'utiliser les interfaces IEnumerable . foreacha une syntaxe très succincte et très facile à comprendre par rapport au style C classique pour les boucles où vous devez vérifier les différentes variables pour voir ce qu'il faisait.

rendement

Une caractéristique moins connue est probablement qu'IEnumerable active également les générateurs en C # avec l'utilisation des instructions yield returnet yield break.

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

Abstractions

Un autre scénario courant en pratique utilise IEnumerable pour fournir des abstractions minimalistes. Comme il s'agit d'une interface minuscule et en lecture seule, vous êtes encouragé à exposer vos collections en tant qu'Enumerable (plutôt que List par exemple). De cette façon, vous êtes libre de changer votre implémentation sans casser le code de votre client (changez List en une LinkedList par exemple).

Je t'ai eu

Un comportement à prendre en compte est que dans les implémentations de streaming (par exemple, récupérer des données ligne par ligne dans une base de données, au lieu de charger tous les résultats en mémoire en premier), vous ne pouvez pas parcourir la collection plus d'une fois. Cela contraste avec les collections en mémoire comme List , où vous pouvez répéter plusieurs fois sans problème. ReSharper, par exemple, a une inspection de code pour l' énumération multiple possible de IEnumerable .

IEnumerator

IEnumerator, d'autre part, est l'interface en arrière-plan qui fait fonctionner IEnumerble-foreach-magic . À proprement parler, il permet des itérateurs explicites.

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

D'après mon expérience, IEnumerator est rarement utilisé dans les scénarios courants en raison de sa syntaxe plus verbeuse et de sa sémantique légèrement déroutante (du moins pour moi; par exemple, MoveNext () renvoie également une valeur, ce que le nom ne suggère pas du tout).

Cas d'utilisation pour IEnumerator

J'ai uniquement utilisé IEnumerator en particulier (niveau légèrement inférieur) des bibliothèques et des frameworks où je fournissais des interfaces IEnumerable . Un exemple est une bibliothèque de traitement de flux de données qui fournissait une série d'objets dans une foreachboucle même si les données en arrière-plan étaient collectées à l'aide de divers flux de fichiers et de sérialisations.

Code client

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

Bibliothèque

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

L'implémentation IEnumerablesignifie essentiellement que l'objet peut être itéré. Cela ne signifie pas nécessairement qu'il s'agit d'un tableau car certaines listes ne peuvent pas être indexées mais vous pouvez les énumérer.

IEnumeratorest l'objet réel utilisé pour effectuer les itérations. Il contrôle le passage d'un objet à l'autre dans la liste.

La plupart du temps, IEnumerable& IEnumeratorsont utilisés de manière transparente dans le cadre d'une foreachboucle.


6

Différences entre IEnumerable et IEnumerator:

  • IEnumerable utilise IEnumerator en interne.
  • IEnumerable ne sait pas quel élément / objet est en cours d'exécution.
  • Chaque fois que nous passons IEnumerator à une autre fonction, il connaît la position actuelle de l'élément / objet.
  • Chaque fois que nous passons une collection IEnumerable à une autre fonction, elle ne connaît pas la position actuelle de l'élément / objet (ne sait pas quel élément son exécution)

    IEnumerable a une méthode GetEnumerator ()

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

IEnumerator possède une propriété appelée Current et deux méthodes, Reset () et MoveNext () (ce qui est utile pour connaître la position actuelle d'un élément dans une liste).

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

5

IEnumerable est une boîte qui contient Ienumerator. IEnumerable est l'interface de base pour toutes les collections. la boucle foreach peut fonctionner si la collection implémente IEnumerable. Dans le code ci-dessous, il explique l'étape d'avoir notre propre énumérateur. Définissons d'abord notre classe dont nous allons faire la collection.

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

Nous allons maintenant définir la classe qui agira comme une collection pour notre client de classe. Notez qu'il implémente l'interface IEnumerable. De sorte que nous devons implémenter la méthode GetEnumerator. Cela renverra notre énumérateur personnalisé.

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);
    }
}

Nous allons maintenant créer notre propre énumérateur personnalisé comme suit. Nous devons donc implémenter la méthode MoveNext.

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

Maintenant, nous pouvons utiliser une boucle foreach sur notre collection comme ci-dessous;

    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

Une compréhension du modèle d'itérateur vous sera utile. Je recommande la même lecture.

Modèle d'itérateur

À un niveau élevé, le modèle d'itérateur peut être utilisé pour fournir une méthode standard d'itération à travers des collections de tout type. Nous avons 3 participants dans le modèle d'itérateur, la collection réelle (client), l'agrégateur et l'itérateur. L'agrégat est une interface / classe abstraite qui a une méthode qui retourne un itérateur. Iterator est une classe d'interface / abstraite qui a des méthodes nous permettant de parcourir une collection.

Afin d'implémenter le modèle, nous devons d'abord implémenter un itérateur pour produire un béton qui peut itérer sur la collection concernée (client). Ensuite, la collection (client) implémente l'agrégateur pour renvoyer une instance de l'itérateur ci-dessus.

Voici le diagramme UML Modèle d'itérateur

Donc, fondamentalement en c #, IEnumerable est l'agrégat abstrait et IEnumerator est l'itérateur abstrait. IEnumerable a une seule méthode GetEnumerator qui est responsable de la création d'une instance de IEnumerator du type souhaité. Les collections comme les listes implémentent l'IEnumerable.

Exemple. Supposons que nous ayons une méthode getPermutations(inputString)qui renvoie toutes les permutations d'une chaîne et que la méthode renvoie une instance deIEnumerable<string>

Afin de compter le nombre de permutations, nous pourrions faire quelque chose comme ci-dessous.

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

Le compilateur c # convertit plus ou moins ce qui précède en

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

Si vous avez des questions, n'hésitez pas à demander.


2

Une contribution mineure.

Comme beaucoup d'entre eux expliquent «quand utiliser» et «utiliser avec foreach». J'ai pensé à ajouter une autre différence entre les États ici comme demandé en question à propos de la différence entre les deux IEnumerable et IEnumerator.

J'ai créé l'exemple de code ci-dessous basé sur les fils de discussion ci-dessous.

IEnumerable, IEnumerator vs foreach, quand utiliser quoi Quelle est la différence entre IEnumerator et IEnumerable?

L'énumérateur préserve l'état (position d'itération) entre les appels de fonction tandis que les itérations, en revanche, l'énumérateur ne le fait pas.

Voici l'exemple testé avec des commentaires à comprendre.

Experts, veuillez m'ajouter / corriger.

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

J'ai remarqué ces différences:

A. Nous itérons la liste de différentes manières, foreach peut être utilisé pour IEnumerable et while loop pour IEnumerator.

B. IEnumerator peut se souvenir de l'index en cours lorsque nous passons d'une méthode à une autre (il commence à travailler avec l'index en cours) mais IEnumerable ne peut pas se souvenir de l'index et il réinitialise l'index au début. Plus dans cette vidéo https://www.youtube.com/watch?v=jd3yUjGc9M0


1

IEnumerableet les IEnumeratordeux sont des interfaces en C #.

IEnumerableest une interface définissant une méthode unique GetEnumerator()qui renvoie une IEnumeratorinterface.

Cela fonctionne pour un accès en lecture seule à une collection qui implémente qui IEnumerablepeut être utilisée avec une foreachinstruction.

IEnumeratora deux méthodes, MoveNextet Reset. Il possède également une propriété appelée Current.

Ce qui suit montre l'implémentation de IEnumerable et 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
  */
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.