web-dev-qa-db-fra.com

Distinction entre itérateur et énumérateur

Une question d'entrevue pour un travail .NET 3.5 est "Quelle est la différence entre un itérateur et un énumérateur"?

C'est une distinction fondamentale à faire, avec LINQ, etc.

Quoi qu'il en soit, quelle est la différence? Je n'arrive pas à trouver une définition solide sur le net. Ne vous y trompez pas, je peux trouver la signification des deux termes mais j'obtiens des réponses légèrement différentes. Quelle serait la meilleure réponse pour un entretien?

IMO un itérateur "itère" sur une collection, et un énumérateur fournit la fonctionnalité pour itérer, mais cela doit être appelé.

En outre, l'utilisation du mot-clé yield est censée enregistrer l'état. Quel est exactement cet état? Existe-t-il un exemple de cet avantage?

70
GurdeepS

Itérer signifie répéter certaines étapes, tandis qu'énumérer signifie parcourir toutes les valeurs d'une collection de valeurs. L'énumération nécessite donc généralement une certaine forme d'itération.

De cette façon, l'énumération est un cas spécial d'itération où l'étape obtient une valeur d'une collection.

Notez que "habituellement" - l'énumération peut également être effectuée de manière récursive, mais la récursivité et l'itération sont si étroitement liées que je ne me soucierais pas de cette petite différence.

Vous pouvez également énumérer des valeurs que vous ne stockez pas explicitement dans une collection. Par exemple, vous pouvez énumérer le nombre naturel, les nombres premiers ou quoi que ce soit, mais vous calculeriez ces valeurs pendant l'énumération et ne les récupérez pas dans une collection physique. Vous comprenez ce cas comme l'énumération d'une collection virtuelle avec ses valeurs définies par une logique.


Je suppose que Reed Copsey a compris. En C #, il existe deux façons principales d'énumérer quelque chose.

  1. Implémentez Enumerable et une classe implémentant IEnumerator
  2. Implémentez un itérateur avec l'instruction yield

La première méthode est plus difficile à implémenter et utilise des objets pour l'énumération. La deuxième manière est plus facile à implémenter et utilise des continuations.

51
Daniel Brückner

En C # 2+, itérateurs sont un moyen pour le compilateur de générer automatiquement les interfaces IEnumerable et/ou IEnumerable <T> pour vous.

Sans itérateurs, vous devez créer une classe implémentant IEnumerator , y compris Current, MoveNext et Reset. Cela nécessite une bonne quantité de travail. Normalement, vous créez une classe privée qui implémente IEnumerator <T> pour votre type, puis yourClass.GetEnumerator () construit cette classe privée et la renvoie.

Les itérateurs sont un moyen pour le compilateur de générer automatiquement cela pour vous, en utilisant une syntaxe simple (yield). Cela vous permet d'implémenter GetEnumerator () directement dans votre classe, sans qu'une deuxième classe (The IEnumerator) ne soit spécifiée par vous. La construction de cette classe, avec tous ses membres, est faite pour vous.

Les itérateurs sont très conviviaux pour les développeurs - les choses se font de manière très efficace, avec beaucoup moins d'efforts.

Lorsque vous utilisez foreach, les deux se comportent de manière identique (à condition que vous écriviez correctement votre IEnumerator personnalisé). Les itérateurs rendent la vie beaucoup plus simple.

43
Reed Copsey

Ce que C # appelle un itérateur est plus couramment (en dehors du monde C #) appelé un générateur ou fonction de générateur (par exemple en Python). Une fonction de générateur est un cas spécialisé de coroutine . Un itérateur (générateur) C # est une forme spéciale d'un énumérateur (un type de données implémentant l'interface IEnumerable).

Je n'aime pas cette utilisation du terme itérateur pour un générateur C # car c'est tout autant un énumérateur qu'un itérateur. Trop tard pour que Microsoft change d'avis.

Par contraste, considérons qu'en C++, un itérateur est une valeur qui est utilisée principalement pour accéder aux éléments séquentiels d'une collection. Il peut être avancé, déréférencé pour récupérer une valeur et testé pour voir si la fin de la collection a été atteinte.

19
cdiggins

"Alors qu'une déclaration foreach est le consommateur de l'énumérateur, un itérateur est le producteur de l'énumérateur."

Ce qui précède explique comment "C # 5.0 In A NutShell" l'explique et m'a été utile.

En d'autres termes, l'instruction foreach utilise MoveNext () et la propriété Current de IEnumerator pour parcourir une séquence, tandis que l'itérateur est utilisé pour produire l'implémentation de IEnumerator qui sera utilisée par l'instruction foreach. En C #, lorsque vous écrivez une méthode d'itérateur contenant une déclaration de rendement, le compilateur génère pour vous un énumérateur privé. Et lorsque vous parcourez les éléments de la séquence, il appellera la propriété MoveNext () et Current de l'énumérateur privé. Ces méthodes/propriétés sont implémentées par votre code dans la méthode itérateur qui sera appelée de manière répétée pour produire des valeurs jusqu'à ce qu'il ne reste plus de valeurs à fournir.

C'est ma compréhension de la façon dont C # définit les énumérateurs et les itérateurs.

12
Ping

Pour comprendre les itérateurs, nous devons d'abord comprendre les énumérateurs.

Les énumérateurs sont des objets spécialisés qui fournissent à l’un les moyens de parcourir une liste ordonnée d’articles un par un (le même genre de chose est parfois appelé "curseur"). Le framework .NET fournit deux interfaces importantes relatives aux énumérateurs: IEnumerator et IEnumerable. Les objets qui implémentent IEnumerator sont eux-mêmes des énumérateurs; ils soutiennent les membres suivants:

  • la propriété Current, qui pointe vers une position sur la liste

  • la méthode MoveNext, qui déplace l'élément courant le long de la liste

  • la méthode Reset, qui déplace l'élément actuel vers sa position initiale (qui est avant le premier élément).

D'un autre côté, les itérateurs implémentent le modèle d'énumérateur. .NET 2.0 a introduit l'itérateur, qui est un énumérateur manifesté par le compilateur. Lorsque l'objet énumérable peut obtenir GetEnumerator, directement ou indirectement, le compilateur génère et renvoie un objet itérateur approprié. Facultativement, l'itérateur peut être un objet énumérable et énumérateur combiné.

L'ingrédient essentiel d'un bloc itératif est la détermination du rendement. Il y a une grande différence entre les itérateurs et les énumérateurs: les itérateurs n'implémentent pas la méthode Reset. La définition de la méthode de réinitialisation sur un itérateur crée une exception.

Le but des itérateurs est de permettre l'implémentation facile des énumérateurs. Lorsqu'une méthode doit renvoyer un énumérateur ou une classe énumérable pour une liste ordonnée d'éléments, elle est écrite de manière à renvoyer chaque élément dans son ordre correct à l'aide de l'instruction "yield".

12
Joshua

Puisqu'aucun exemple n'a été donné, en voici un qui m'a été utile.

Un énumérateur est un objet que vous obtenez lorsque vous appelez .GetEnumerator () sur une classe ou un type qui implémente l'interface IEnumerator. Lorsque cette interface est implémentée, vous avez créé tout le code nécessaire au compilateur pour vous permettre d'utiliser foreach pour "itérer" votre collection.

Cependant, ne confondez pas l'itération de Word avec l'itérateur. L'énumérateur et l'itérateur vous permettent tous les deux d'itérer. L'énumération et l'itération sont fondamentalement le même processus, mais sont implémentées différemment. L'énumération signifie que vous avez implémenté l'interface IEnumerator . L'itération signifie que vous avez créé la construction d'itérateur dans votre classe (illustrée ci-dessous) et que vous appelez foreach sur votre classe, moment auquel le compilateur crée automatiquement la fonctionnalité d'énumérateur pour vous.

Notez également que vous n'avez pas à faire de squat avec votre enquêteur. Vous pouvez appeler MyClass.GetEnumerator() toute la journée et ne rien faire avec (exemple:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator()).

Notez également que votre construction d'itérateur dans votre classe n'est vraiment utilisée que lorsque vous l'utilisez réellement, c'est-à-dire que vous avez appelé foreach sur votre classe.

Voici un exemple d'itérateur de msdn :

public class DaysOfTheWeek : System.Collections.IEnumerable
{

     string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

     //This is the iterator!!!
     public System.Collections.IEnumerator GetEnumerator()
     {
         for (int i = 0; i < days.Length; i++)
         {
             yield return days[i];
         }
     }

}

class TestDaysOfTheWeek
{
    static void Main()
    {
        // Create an instance of the collection class
        DaysOfTheWeek week = new DaysOfTheWeek();

        // Iterate with foreach - this is using the iterator!!! When the compiler
        //detects your iterator, it will automatically generate the Current, 
        //MoveNext and Dispose methods of the IEnumerator or IEnumerator<T> interface
        foreach (string day in week)
        {
            System.Console.Write(day + " ");
        }
    }
}
// Output: Sun Mon Tue Wed Thr Fri Sat
7
richard

"Les itérateurs sont une nouvelle fonctionnalité de C # 2.0. Un itérateur est une méthode, obtenir un accesseur ou un opérateur qui vous permet de prendre en charge chaque itération dans une classe ou une structure sans avoir à implémenter l'intégralité de l'interface IEnumerable. Au lieu de cela, vous ne fournissez qu'un itérateur, qui traverse simplement les structures de données de votre classe. Lorsque le compilateur détecte votre itérateur, il génère automatiquement les méthodes Current, MoveNext et Dispose de l'interface IEnumerable ou IEnumerable. " - msdn

3
John Ellinwood

L'énumération concerne les objets tandis que l'itération ne concerne que les valeurs. L'énumération est utilisée lorsque nous utilisons la table de hachage vectorielle, etc. tandis que l'itération est utilisée dans la boucle while pour la boucle, etc. Je n'ai jamais utilisé le mot clé yield, donc je ne pourrais pas vous le dire.

2
Kredns