Question

I ont une classe C # qui a besoin pour traiter une séquence d'éléments (IEnumerable<T>) à travers une série de méthodes, de sorte que je ne peux pas simplement foreach intérieur d'une méthode. J'appelle .GetEnumerator() et passer cette IEnumerator<T> autour et il fonctionne très bien me donner la flexibilité dont j'ai besoin en boucle à travers une seule séquence.

Maintenant, je veux permettre à d'autres d'ajouter une logique dans ce processus. La façon la plus naturelle de le faire est de leur donner une interface avec une méthode qui accepte la IEnumerator<T>. Facile, fait, et cela fonctionne.

Mais je crains que c'est un anti-modèle. Ils doivent savoir que le IEnumerator<T> a déjà .MoveNext() appelé, afin qu'ils puissent .Current simplement l'accès. De plus, je ne vois pas un précédent pour l'utilisation IEnumerator<T> dans les interfaces à mettre en œuvre.

  1. Quels sont les écueils que je ne suis envisage?
  2. Y at-il un autre motif qui me permettra cette même efficace mécanisme (à savoir que je ne veux pas de copies multiples créés / détruits) sans exposer le IEnumerator<T> lui-même?

Mise à jour: Comme je l'ai mentionné dans un commentaire ci-dessous: Ce que je veux est une sorte de Stream<T> générique. Je dois être en mesure de voir efficacement l'élément suivant (IEnumerator.Current -> .Peek()) et de le consommer (IEnumerator<T>.MoveNext() -> .Pop()).

J'utilisé IEnumerator<T> parce qu'il correspond à l'interface de facture sage. Je préfère utiliser les types de BCL commun quand ils en forme, mais il me semblait que j'abusais celui-ci.

question 3) Y at-il une classe qui correspond à ce besoin? Ou devrais-je simplement créer mon propre flux qui exécute paresseusement le IEnumerator<T> interne? Ensuite, il serait entièrement encapsulé. Je voudrais de ne pas utiliser la plupart des collections existantes car ils ont le stockage interne, alors que je voudrais que le stockage soit le IEnumerable<T> iteslf.


OK il semble que le consensus est que faire pour IEnumerator<T> souvent être un ValueType aussi bien que ne sachant pas a priori l'état du IEnumerator<T>, qu'il est généralement une mauvaise idée de passer autour.

La meilleure suggestion que je l'ai entendu est de créer ma propre classe qui obtient passé autour. Toutes les autres suggestions?

Était-ce utile?

La solution

Si je comprends bien, vous avez un certain nombre de méthodes qui peuvent tous MoveNext d'appel sur la séquence et vous voulez que ces méthodes de coopérer entre-autre, de sorte que vous passez autour d'un IEnumerator<T>. Il y a certainement un peu serré couplage ici, comme vous l'avez mentionné, puisque vous attendez le recenseur d'être dans un état particulier à l'entrée de chaque méthode. On dirait que ce que vous êtes vraiment après ici quelque chose comme la classe Stream, qui est à la fois une collection (un peu) et un iterator (a une notion d'actuel). J'enveloppez votre itération et tout autre Etat dont vous avez besoin dans votre propre classe et ont les différentes méthodes en tant que membres de cette catégorie

Autres conseils

Vous devriez définitivement pas passer le IEnumerator<T> autour. En dehors de toute autre chose, il pourrait avoir des très effets bizarres dans certains cas. Que voulez-vous attendre à arriver ici, par exemple?

using System;
using System.Collections.Generic;

class Test
{
    static void ShowCurrentAndNext(IEnumerator<int> iterator)        
    {
        Console.WriteLine("ShowCurrentAndNext");
        Console.WriteLine(iterator.Current);
        iterator.MoveNext(); // Let's assume it returns true
        Console.WriteLine(iterator.Current);
    }

    static void Main()
    {
        List<int> list = new List<int> { 1, 2, 3, 4, 5 };
        using (var iterator = list.GetEnumerator())
        {
            iterator.MoveNext(); // Get things going
            ShowCurrentAndNext(iterator);
            ShowCurrentAndNext(iterator);
            ShowCurrentAndNext(iterator);
        }
    }
}

Quelques changements à essayer:

using (List<int>.Enumerator iterator = list.GetEnumerator())

et

using (IEnumerator<int> iterator = list.GetEnumerator())

Essayez de prédire les résultats dans chaque cas:)

Maintenant, il est vrai que est un exemple particulièrement mal, mais il fait preuve de certains cas d'angle associés à passer autour de l'état mutable. Je vous encourage vivement à effectuer toutes vos itération dans une méthode « centrale » qui appelle à d'autres méthodes appropriées juste avec la valeur actuelle.

Je conseille vivement contre le passage du recenseur lui-même autour; quelle raison avez-vous pour cela, à part avoir besoin de la valeur actuelle?

À moins que je manque quelque chose d'évident, je recommande d'avoir vos fonctions utilitaires prennent simplement le type que vous êtes en tant que paramètre énumération, ont alors une seule boucle de foreach externe qui gère le dénombrement proprement dit.

Peut-être que vous pouvez fournir des informations supplémentaires pour expliquer pourquoi vous avez pris cette décision de conception jusqu'à présent.

me semble que vous pourriez bénéficier d'utiliser un événement afin que vous puissiez pousser notification des articles à traiter vers les auditeurs. événements .NET réguliers sont traités dans l'ordre où ils se sont abonnées, vous pourriez opter pour une approche plus explicite si la commande est nécessaire.

Vous pouvez également à examiner le cadre réactif.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top