Domanda

Ho un # di classe C, che ha bisogno di elaborare una serie di elementi (IEnumerable<T>) attraverso una serie di metodi, quindi non posso semplicemente foreach all'interno di un metodo. Chiamo .GetEnumerator() e passare questo IEnumerator<T> intorno e funziona benissimo avermi dato la flessibilità ho bisogno, mentre scorrendo una singola sequenza.

Ora voglio consentire ad altri di aggiungere la logica in questo processo. Il modo più naturale per farlo è dare loro un'interfaccia con un metodo che accetta il IEnumerator<T>. Facile, fatto, e funziona.

Ma io sono preoccupato del fatto che si tratta di un anti-modello. Devono sapere che il IEnumerator<T> ha già avuto .MoveNext() chiamato, in modo che possano semplicemente l'accesso .Current. Inoltre non vedo alcun precedente per l'utilizzo IEnumerator<T> nelle interfacce da attuare.

  1. Quali insidie ??sono io, non considerando?
  2. C'è un altro motivo che mi permetterà questo stesso efficace Meccanismo (vale a dire che non voglio più copie in fase di creazione / distrutto) senza esporre il IEnumerator<T> stessa?

Aggiornamento: Come ho già detto in un commento qui sotto: Quello che voglio è una sorta di Stream<T> generico. Ho bisogno di essere in grado di vedere in modo efficace la voce successiva (IEnumerator.Current -> .Peek()) e consumarlo (IEnumerator<T>.MoveNext() -> .Pop()).

ho usato IEnumerator<T> perché adatta l'interfaccia disegno di legge saggia. Io preferisco usare tipi comuni BCL quando si inseriscono, ma sembrava che stavo abusando questo.

Quindi, domanda 3) v'è una classe che si adatta a questa esigenza? O devo solo creare la mia Stream che esegue pigramente il IEnumerator<T> internamente? Poi sarebbe del tutto incapsulato. Mi piacerebbe non utilizzare molte delle collezioni esistenti in quanto hanno memoria interna, mentre mi piacerebbe l'archiviazione di essere il IEnumerable<T> iteslf.


OK suona come il consenso è che fare per IEnumerator<T> spesso essere un ValueType così come non sapendo a priori lo stato del IEnumerator<T>, che è generalmente una cattiva idea di passare in giro.

Il miglior suggerimento che ho sentito è quello di creare la mia classe che viene passato in giro. Altri suggerimenti?

È stato utile?

Soluzione

Se ho capito bene, si ha una serie di metodi che possono essere tutti MoveNext chiamata in sequenza e si desidera che questi metodi a cooperare con l'un l'altro, in modo da passare intorno ad un IEnumerator<T>. C'è sicuramente un po 'stretto accoppiamento qui, come lei ha ricordato, dal momento che ci si aspetta l'enumeratore di essere in uno stato particolare all'ingresso di ciascun metodo. Suona come quello che sei veramente dopo qui è qualcosa di simile classe Stream, che è sia un insieme (o quasi) e un iteratore (ha una nozione di posizione corrente). Vorrei avvolgere il vostro iterazione e qualsiasi altro stato necessario nella propria classe e hanno i vari metodi come membri di quella classe

Altri suggerimenti

Si dovrebbe sicuramente non passare il IEnumerator<T> intorno. A parte tutto, potrebbe avere qualche molto effetti bizzarri in alcuni casi. Che cosa vi aspettate che accada qui, per esempio?

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

Un paio di modifiche da provare:

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

e

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

cercare di prevedere i risultati in ogni caso:)

Ora è vero che è un esempio particolarmente male, ma lo fa dimostrare alcuni casi angolo connessi con il passaggio di stato in giro mutevole. Vorrei vivamente di eseguire tutti i vostri iterazione in un metodo "centrale" che mette in appositi altri metodi solo con il valore corrente.

Vi consiglio caldamente contro passando l'enumeratore in sé intorno; quale motivo avete per questo, a parte che necessitano di valore corrente?

A meno che non mi manca qualcosa di ovvio, mi sento di raccomandare avere le funzioni di utilità semplicemente prendere il tipo che si sta enumerando come parametro, quindi avere un unico ciclo foreach esterna che gestisce l'enumerazione attuale.

Forse si può fornire alcune informazioni aggiuntive sul motivo per cui hai fatto questa decisione di progettazione fino ad ora.

Sembra a me come si potrebbe trarre vantaggio dall'utilizzo di un evento in modo da poter spingere la notifica di elementi da elaborare fuori per gli ascoltatori. Eventi regolari .NET vengono gestiti nell'ordine in cui sei iscritto, per cui si potrebbe andare per un approccio più esplicito se è richiesta l'ordinazione.

Potrebbe piacerti anche a guardare il quadro reattivo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top