2009-07-06 8 views
22

Je passais par IEnumerable et IEnumerator, mais je ne pouvais pas obtenir un point clairement .. si nous avons foreach, alors pourquoi avons-nous besoin de ces deux interfaces? Y at-il un scénario où nous devons utiliser des interfaces. Si oui, alors quelqu'un peut-il expliquer avec un exemple. Toutes les suggestions et remarques sont les bienvenues. Merci.IEnumerable, IEnumerator vs foreach, quand utiliser

Répondre

46

foreachutilise les interfaces dans de nombreux cas. Vous avez besoin des interfaces si vous voulez mettre en œuvre une séquence que foreach peut alors utiliser. (Les blocs d'itérateur rendent généralement cette tâche d'implémentation très simple cependant.)

Cependant, juste parfois il peut être utile d'utiliser directement les itérateurs. Un bon exemple est lorsque vous essayez de «jumeler» deux séquences différentes. Par exemple, supposons que vous receviez deux séquences - l'une de noms, l'une d'âges, et que vous voulez imprimer les deux ensemble. Vous pouvez écrire:

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages) 
{ 
    using (IEnumerator<int> ageIterator = ages.GetEnumerator()) 
    { 
     foreach (string name in names) 
     { 
      if (!ageIterator.MoveNext()) 
      { 
       throw new ArgumentException("Not enough ages"); 
      } 
      Console.WriteLine("{0} is {1} years old", name, ageIterator.Current); 
     } 
     if (ageIterator.MoveNext()) 
     { 
      throw new ArgumentException("Not enough names"); 
     } 

    } 
} 

De même, il peut être utile d'utiliser l'itérateur si vous voulez traiter (par exemple) le premier élément différemment du reste:

public T Max<T>(IEnumerable<T> items) 
{ 
    Comparer<T> comparer = Comparer<T>.Default; 

    using (IEnumerator<T> iterator = items.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      throw new InvalidOperationException("No elements"); 
     } 
     T currentMax = iterator.Current; 

     // Now we've got an initial value, loop over the rest 
     while (iterator.MoveNext()) 
     { 
      T candidate = iterator.Current; 
      if (comparer.Compare(candidate, currentMax) > 0) 
      { 
       currentMax = candidate; 
      } 
     } 
     return currentMax; 
    } 
} 

Maintenant, si vous Vous êtes intéressé par la différence entre IEnumerator<T> et IEnumerable<T>, vous pourriez vouloir penser à cela en termes de base de données: pensez à IEnumerable<T> en tant que table, et IEnumerator<T> en tant que curseur. Vous pouvez demander à une table de vous donner un nouveau curseur, et vous pouvez avoir plusieurs curseurs sur la même table en même temps.

Cela peut prendre un certain temps avant que la différence ne se produise, mais rappelez-vous qu'une liste (ou tableau, ou autre) n'a aucun concept de "où vous êtes dans la liste" mais un itérateur sur cette liste/array/whatever est-ce que ce bit d'état est utile?

+0

Merci Jon pour toute votre aide. Je l'ai eu maintenant et étudiera plus pour le rendre clair. Aussi, je trouve le lien suivant très utile: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

+0

Ceci est un exemple d'où vous êtes coincé en utilisant IEnumerator juste rester efficace. http://stackoverflow.com/questions/1018407/what-is-the-most-elegant-way-to-get-a-set-of-items-by-index-from-a-collection/1025137#1025137 –

+0

@Jon Skeet J'ai vraiment aimé la façon dont vous avez codé la méthode Max . J'ai une question. vous avez utilisé l'utilisation de construct avec IEnumberator. Je sais que l'usage dispose de ce qui s'y trouve(). Pourquoi l'avez-vous utilisé sur IEnumberator? –

8

Ce que Jon a dit.

  • IEnumerable ou IEnumerable<T>: en mettant en œuvre ce un objet indique qu'il peut vous donner un itérateur que vous pouvez utiliser pour traverser sur la séquence/collection/définir
  • IEnumerator ou IEnumerator<T>: si vous appelez la méthode GetEnumerator définie Dans l'interface précédente, vous obtenez un objet itérateur en tant que référence IEnumerator. Cela vous permet d'appeler MoveNext() et obtenir l'objet en cours.
  • foreach: est une construction/façade C# dans un sens où vous n'avez pas besoin de savoir comment cela fonctionne sous le capot. Il obtient en interne l'itérateur et appelle les bonnes méthodes pour que vous puissiez vous concentrer sur ce que vous voulez faire avec chaque élément (le contenu du bloc foreach). La plupart du temps, vous auriez besoin de foreach sauf si vous implémentez votre propre type ou itération personnalisée, auquel cas vous devez apprendre à connaître les deux premières interfaces.
+0

Merci Gishu de me l'avoir expliqué plus clairement. aussi je trouve ce lien très utile: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

6

Gardez à l'esprit que vous ne ont à mettre en œuvre IEnumerator et varients de celui-ci à utiliser foreach - IIRC, tout ce qu'il a besoin est une méthode GetEnumerator() qui retourne un objet qui a une méthode MoveNext() retour un bool, et une propriété Current retournant un objet. Vous n'avez pas besoin d'utiliser IEnumerator et IEnumerable, bien que ce soit généralement une très bonne idée de le faire. Voir here pour plus d'informations.

+0

C'est une vieille bête étrange, celle-là - vous pouvez implémentez simplement les deux méthodes. Le gros problème avec cela est que le système de type ne sait pas que la chose est énumérable, donc j'imagine que vous auriez du mal à l'utiliser avec, disons, Linq to Objects. –

+3

Oui, c'est bizarre. La raison pour laquelle nous prenons en charge cette fonctionnalité est que vous pouvez écrire une collection d'entiers dans C# 1.0 et les énumérer sans boxe. Maintenant que nous avons IE , il n'y a plus besoin de l'approche "pattern". –

+1

@Eric Lippert: Cette fonctionnalité présente un autre avantage: elle permet d'éviter les allocations de tas pour les énumérateurs de structure, bien que je suggère que les classes dont les méthodes GetEnumerator renvoient une structure aient des méthodes IEnumerable.GetEnumerator qui retournent des classes. – supercat

Questions connexes