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?
c#
ienumerable
ienumerator
prodev42
la source
la source
Réponses:
Vous n'utilisez pas
IEnumerable
"over"foreach
. L'implémentationIEnumerable
rendforeach
possible l' utilisation .Lorsque vous écrivez du code comme:
il est fonctionnellement équivalent à l'écriture:
Par «fonctionnellement équivalent», je veux dire que c'est en fait ce que le compilateur transforme le code. Vous ne pouvez pas utiliser
foreach
surbaz
dans cet exemple à moinsbaz
que des outilsIEnumerable
.IEnumerable
signifie quebaz
met en œuvre la méthodeL'
IEnumerator
objet renvoyé par cette méthode doit implémenter les méthodeset
La première méthode passe à l'objet suivant dans l'
IEnumerable
objet qui a créé l'énumérateur, en retournantfalse
si 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émenteIEnumerable
, vous pouvez rendre votre classe utilisable dans lesforeach
instructions en implémentantIEnumerable
(et en créant une classe énumérateur que sa nouvelleGetEnumerator
méthode retournera).la source
bool MoveNext()
méthode et uneCurrent
proprié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.iterator
?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:
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:
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:
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:
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:
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:
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:
Cependant, si vous préférez masquer la fonctionnalité de IEnumerable au niveau de l'objet, utilisez simplement l'implémentation d'interface explicite:
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
la source
Garage
qui obtientcarArray
? De cette façon, vous n'avez pas àGetEnumerator
vous implémenter , carArray
cela se fait déjà. Par exempleforeach(Car c in carLot.getCars()) { ... }
Implémenter IEnumerable signifie que votre classe retourne un objet IEnumerator:
L'implémentation d'IEnumerator signifie que votre classe renvoie les méthodes et les propriétés d'itération:
C'est de toute façon la différence.
la source
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:
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:
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.
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!)
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).
la source
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.
la source
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.
la source
Considérez les objets énumérables comme des listes, des piles, des arbres.
la source
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
Je pense que la
foreach
boucle est l'une des principales raisons d'utiliser les interfaces IEnumerable .foreach
a 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 return
etyield break
.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.
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
foreach
boucle 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
Bibliothèque
la source
L'implémentation
IEnumerable
signifie 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.IEnumerator
est 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
&IEnumerator
sont utilisés de manière transparente dans le cadre d'uneforeach
boucle.la source
Différences entre IEnumerable et IEnumerator:
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 ()
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).
la source
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.
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é.
Nous allons maintenant créer notre propre énumérateur personnalisé comme suit. Nous devons donc implémenter la méthode MoveNext.
Maintenant, nous pouvons utiliser une boucle foreach sur notre collection comme ci-dessous;
la source
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
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.
Le compilateur c # convertit plus ou moins ce qui précède en
Si vous avez des questions, n'hésitez pas à demander.
la source
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.
la source
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
la source
IEnumerable
et lesIEnumerator
deux sont des interfaces en C #.IEnumerable
est une interface définissant une méthode uniqueGetEnumerator()
qui renvoie uneIEnumerator
interface.Cela fonctionne pour un accès en lecture seule à une collection qui implémente qui
IEnumerable
peut être utilisée avec uneforeach
instruction.IEnumerator
a deux méthodes,MoveNext
etReset
. Il possède également une propriété appeléeCurrent
.Ce qui suit montre l'implémentation de IEnumerable et IEnumerator.
la source
la source