Est-il possible de cloner un IEnumerable<T> exemple, l'enregistrement d'une copie de l'itération de l'état?
J'aimerais créer une copie d'un IEnumerator<T>
afin que je puisse redémarrer le processus d'énumération à partir d'un endroit particulier de la collection. Clairement, il n'y a aucun avantage à faire des collections qui mettent en œuvre des IList
, depuis que nous puissions nous souvenir de l'indice d'intérêt.
Est-il un moyen astucieux pour accomplir cette tâche en utilisant une combinaison de yield
états et Linq fonctions? Je ne pouvais pas trouver un Clone()
méthode pour copier l'agent recenseur, et voudrais éviter d'utiliser Enumerable.Skip()
pour repositionner un nouvel agent recenseur souhaité la reprise point.
Aussi, j'aimerais garder les solutions aussi générique que possible, et de ne pas dépendre de l'état des collections.
C'est juste une idée que j'ai eu l'autre jour. Si c'était possible, il serait un moyen efficace de permettre à un enquêteur pour être utilisé comme un pointeur (qui ne peut être incrémenté), et pourrait permettre intelligent implémentations de recherche binaire sur la non-indexable collections.
J'y ai pensé pendant un certain temps maintenant, et de réaliser que sans l'accès aux éléments de la collection, ou un moyen de l'indice, il n'y a vraiment aucun moyen d'aller à ce sujet, à moins que la nouvelle numérisation de la collection est acceptable. En utilisant la sérialisation binaire de cloner l'itérateur est une option, mais qui ouvre une autre boîte de pandore tous ensemble.
Pensé que je devrais vous donner une mise à jour. La réelle Énumérateur de l'état de la machine peut être cloné comme je l'ai montré dans ma réponse ci-dessous. Il n'énumère pas, c'est juste des clones de l'agent recenseur.
Le problème est le typecase à
IEnumerator<T>
. Par exemple. List<int>.Enumerator
est une struct. Normalement, vous pouvez simplement l'attribuer à préserver l'état. Si vous typecase à la IEnumerator<T>
interface, il va devenir un referencetype.OriginalL'auteur Steve Guidi | 2009-12-16
Vous devez vous connecter pour publier un commentaire.
Le meilleur que vous pourriez faire est d'écrire quelque chose qui permet de garder une mémoire tampon (peut-être un
Queue<T>
) de données consommé de l'un et pas l'autre (ce qui serait gênant/cher si vous avez avancé un itérateur de 1M positions, mais à gauche de l'autre). Je vraiment pense que vous feriez mieux de repenser la conception, si, et seulement à l'aide deGetEnumerator()
(c'est à dire un autreforeach
) pour démarrer de nouveau - ou de la mémoire tampon de données (s'il est court) dans une liste/tableau/whatever.Rien d'élégant construit en.
Mise à jour: peut-être une alternative intéressante design ici est "PushLINQ"; plutôt que de cloner l'itérateur, il permet à plusieurs "choses" à consommer les mêmes données-alimentation en même temps.
Dans cet exemple (levée de Jon de page) nous calculons plusieurs agrégats en parallèle:
Non, il couvre Jon Skeet du compte, quand il est endormi. Jon skeet ne dort pas, alors il (Skeet) couvre Marc de compte, quand il est censé être endormi. 😉
pah! Le sommeil est pour les faibles! Ensuite, vous serez en suggérant une pause déjeuner? La folie je vous dis, de la folie!
OriginalL'auteur Marc Gravell
Il n'y a pas de manière générale, pour ce faire, depuis un iEnumerable peut dépendre des aspects arbitraires de l'état du système qui ne peuvent pas être détectés par la Réflexion ou par tout autre moyen. Par exemple, un PaperTapeReader classe peut implémenter un agent recenseur qui lit les caractères à partir de la bande jusqu'à ce que le capteur indique il n'y a plus de bande dans la machine. L'état d'un tel agent recenseur serait l'emplacement physique de la bande, qui pourrait être impossible de restaurer la programmation.
Donné un iEnumerable, il serait possible de produire deux ou plusieurs iEnumerables, chacun de qui agirait comme l'original ou clone de celui-ci. MoveNext les demandes de celui qui était "le plus loin le long de la" permettrait de lire les nouvelles données de l'original iEnumerable et de la mémoire tampon pour les autres. À moins que l'original iEnumerable prend en charge de telles "hook" fonctionnalité, cependant, je ne pense pas qu'il y avait aucun moyen de s'accrocher à ses données comme il vient dans.
OriginalL'auteur supercat
C'est complètement pas une réponse, mais l'expérience de pensée que j'ai trouvé intéressant...si vous avez un basé sur le rendement IEnumerable, je suppose que tu sais tout est généré par le compilateur de la magie. Si vous avez une telle bête, vous pourrait faire quelque chose comme ça... 😉
Ouais, les "variables d'état" au sein de l'généré classe d'énumération sont les choses que l'on a besoin de signet dans le but de faire un continuation-comme le mouvement comme cela, bien sûr, puisque l'ensemble de l'état et de la valeur des bits et des bobs sont nom-mutilé, la seule "sécurité" (et j'utilise ce terme vaguement) est de copier l'ensemble de l'état interne des champs. Pour être précis, tho, vous ne voudriez pas être la copie de l'ensemble de l'énumération ici, probablement 3-4 champs en moyenne.
(bien sûr, on pourrait essayer de mettre en œuvre une bonne continuation monade en C#, mais c'est un tout autre animal) 😉
Votre réponse m'a inspiré pour faire un clone de l'outil. Vous pouvez économiser de la place et de le reprendre plus tard. Comme le titre dit clone, j'ai créé une nouvelle instance.
OriginalL'auteur JerKimball
Voulez-vous être en mesure de sauver l'état, continuer l'énumération, puis retour à l'état enregistré, ou vous voulez tout simplement être en mesure d'énumérer, faire quelques autres trucs, puis continuer l'énumération?
Si c'est celui-ci, quelque chose comme ce qui suit pourrait fonctionner:
Maintenant vous pouvez le faire:
OriginalL'auteur ICR
JerKimball avait une approche intéressante. J'essaie de le prendre au prochain niveau. On utilise à cette réflexion afin de créer une nouvelle instance, puis définit les valeurs sur la nouvelle instance. J'ai également trouvé ce chapitre à partir de C# en Profondeur pour être très utile.
Itérateur bloquer les détails de mise en œuvre: auto-généré de l'état des machines
OriginalL'auteur BenMaddox
Donc ce que vous vraiment veux, c'est être en mesure de reprendre une itération plus tard, ai-je raison? Et le clonage de l'enquêteur ou de la collection est la façon dont vous pensez que vous auriez du faire une telle chose?
Vous pourriez faire une classe qui encapsule un IEnumerable, et expose une coutume énumérateur qui, en interne, des clones de l'intérieur IEnumerable, et énumère ensuite. Puis, à l'aide de GetEnumerator() serait de vous donner un énumérateur qui pourrait être passé autour.
Cela permettrait de créer une copie supplémentaire de l'interface IEnumerable pour chaque agent Recenseur "en vol", mais je pense qu'il serait de répondre à vos besoins.
IList<T>
rend la solution facile, que je peux écrire mon propre classe iterator qui suit les indices, mais je voudrais éviter si possible. Pourriez-vous nous donner un bref pseudo-code exemple pour votre solution? Je ne suis pas clair sur la façon dont vous avez l'intention sur le clonage de l'intérieurIEnumerable
instance.Ah, si vous voulez faire une itération à partir d'un point, puis de reprendre cette itération de dos à un certain point précédent. Je voudrais faire une nouvelle collection, puis, comme une solution à ce problème est d'aller à la réduire à cela de toute façon.
OriginalL'auteur kyoryu