Frage

Ich habe eine C # -Klasse, die eine Folge von Elementen (IEnumerable<T>) über eine Reihe von Methoden verarbeiten muss, so dass ich nicht einfach in einer Methode foreach. Ich nenne .GetEnumerator() und geben diese IEnumerator<T> um und es funktioniert super mir die Flexibilität, ich brauche, während sie durch eine einzige Sequenz geschleift wird.

Jetzt möchte ich, damit andere Logik in diesen Prozess hinzuzufügen. Der natürlichste Weg, dies zu tun, ist ihr eine Schnittstelle mit einer Methode geben, die die IEnumerator<T> akzeptiert. Einfach, getan, und es funktioniert.

Aber ich bin besorgt, dass dies ein anti-Muster. Sie müssen wissen, dass die IEnumerator<T> bereits .MoveNext() hatte genannt, so können sie einfach Zugang .Current. Plus Ich sehe keinen Präzedenzfall für die Verwendung von IEnumerator<T> in Schnittstellen implementiert werden.

  1. Was Tücken bin ich nicht in Erwägung?
  2. Gibt es ein anderes Muster, das mir den gleichen effizient ermöglicht Mechanismus (das heißt ich will nicht mehr Kopien erstellt werden / zerstört) ohne Aussetzen des IEnumerator<T> selbst?

Update: Wie ich in einem Kommentar erwähnt unter: Was ich will, ist eine Art von generischen Stream<T>. Ich muss in der Lage sein, um effektiv den nächsten Punkt zu sehen (IEnumerator.Current -> .Peek()) und verbrauchen (IEnumerator<T>.MoveNext() -> .Pop()).

Ich habe IEnumerator<T>, weil sie die Rechnung Schnittstelle weise passen. Ich ziehe es gemeinsame BCL-Typen zu verwenden, wenn sie passen, aber es schien, als ob ich diesen missbrauche.

So Frage 3) Gibt es eine Klasse, die diesen Bedarf passt? Oder sollte ich meine eigenen Strom nur schaffen, die gemächlich die IEnumerator<T> intern ausführt? Dann wäre es völlig eingekapselt werden. Ich möchte nicht viele der bestehenden Sammlungen verwenden, wie sie interne Speicher haben, während ich die Speicher möchte die IEnumerable<T> iteslf zu sein.


OK, es klingt wie der Konsens, dass ist es oft IEnumerator<T> ein ValueType Befinden als auch als a priori nicht den Zustand des IEnumerator<T> zu wissen, dass es in der Regel eine schlechte Idee, es zu laufen um.

Die beste Empfehlung, die ich gehört habe, ist meine eigene Klasse zu schaffen, die herumgereicht wird. Alle anderen Vorschläge?

War es hilfreich?

Lösung

Wenn ich das richtig verstehen, haben Sie eine Reihe von Methoden, die alle Aufruf Movenext auf der Sequenz können und Sie diese Methoden wollen mit jedem-anderen kooperieren, so dass Sie ein IEnumerator<T> passieren herum. Es gibt definitiv einige eng hier Kopplung, wie Sie erwähnt haben, da Sie die enumerator erwarten jede Methode am Eingang in einem bestimmten Zustand zu sein. Es klingt wie das, was Sie wirklich nach hier ist so etwas wie die Stream-Klasse, die beide eine Sammlung ist (Art) und ein Iterator (eine Vorstellung der aktuellen Lage hat). Ich würde wickeln Sie Ihre Iteration und anderen Zustand, den Sie in Ihrer eigenen Klasse müssen und habe die verschiedenen Methoden als Mitglieder dieser Klasse

Andere Tipps

Sie sollten auf jeden Fall nicht die IEnumerator<T> passieren herum. Abgesehen von allem anderen, könnte es haben einige sehr bizarre Effekte in einigen Fällen. Was würden Sie erwarten, zum Beispiel hier geschehen?

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);
        }
    }
}

Ein paar Änderungen, um zu versuchen:

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

und

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

Versuchen Sie, die Ergebnisse in jedem Fall vorherzusagen:)

Jetzt allerdings ist das ein besonders böses Beispiel, aber es hat einige Ecke Fälle mit, das um wandelbar Zustand assoziiert zu demonstrieren. Ich möchte Sie ermutigt alle Ihre Iteration in einem „zentralen“ Verfahren durchzuführen, die in geeignete andere Methoden nur Anrufe mit dem aktuellen Wert.

Ich würde dringend davon abraten, das Bestehen der enumerator sich um; was Grund haben Sie für diesen, abgesehen von dem aktuellen Wert um?

Wenn ich offensichtlich etwas fehlt bin, würde ich empfehlen, Ihre Dienstprogramm mit Funktionen einfach die Art nehmen, dass Sie als Parameter sind aufzählt, dann haben eine einzige äußere foreach Schleife, dass Griffe die tatsächliche Aufzählung.

Vielleicht können Sie einige zusätzliche Informationen liefern, warum Sie diese Design-Entscheidung gemacht habe, so weit.

Sounds für mich wie Sie so ein Ereignis verwenden, könnten profitieren, dass Sie eine Benachrichtigung von Elementen schieben können Zuhörer verarbeitet geführt werden. Regelmäßige .NET Ereignisse behandelt werden in der Reihenfolge, wie sie sind abonnieren, so dass Sie für einen expliziten Ansatz gehen könnten, wenn Bestellung erforderlich ist.

Sie können auch mögen Blick auf die Reactive Framework.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top