2009-04-04 25 views
62

Una domanda di intervista per un lavoro .NET 3.5 è "Qual è la differenza tra un iteratore e un enumeratore"?Distinzione tra iteratore ed enumeratore

Questa è una distinzione di base per fare, quello che con LINQ, ecc

In ogni caso, qual è la differenza? Non riesco a trovare una definizione solida sulla rete. Non commettere errori, riesco a trovare il significato dei due termini, ma ottengo risposte leggermente diverse. Quale sarebbe la migliore risposta per un'intervista?

IMO un iteratore "itera" su una raccolta e un enumeratore fornisce la funzionalità per iterare, ma questo deve essere chiamato.

Inoltre, utilizzando la parola chiave yield si dice per salvare lo stato. Cos'è esattamente questo stato? C'è un esempio di questo beneficio che si verifica?

risposta

42

Iterare significa ripetere alcuni passaggi, mentre enumerare significa passare attraverso tutti i valori in un insieme di valori. Quindi enumerare di solito richiede qualche forma di iterazione.

In questo modo, l'enumerazione è un caso speciale di iterazione in cui il passaggio riceve un valore da una raccolta.

Nota il "solito" - enumerare può anche essere eseguito in modo ricorsivo, ma ricorsione e iterazione sono così strettamente correlati che non mi interesserebbe questa piccola differenza.

È anche possibile enumerare valori che non vengono memorizzati in modo esplicito in una raccolta. Ad esempio, è possibile enumerare il numero naturale, i numeri primi o qualsiasi altra cosa, ma si dovrebbero calcolare questi valori durante l'enumerazione e non recuperarli da una raccolta fisica. Capisci questo caso come enumerare una collezione virtuale con i suoi valori definiti da una qualche logica.


Suppongo che Reed Copsey abbia capito il punto. In C# ci sono due modi principali per enumerare qualcosa.

  1. Implementare Enumerable e una classe che implementa IEnumerator
  2. attuare un iteratore con il yield dichiarazione

Il primo modo è più difficile da implementare e utilizza oggetti per l'enumerazione. Il secondo modo è più facile da implementare e utilizza le continuazioni.

+5

In C#, tuttavia, un iteratore è un costrutto specifico e speciale, nonché solo il verbo che descrive il termine. Un enumeratore, inoltre, è un'interfaccia specifica. I due hanno un significato nettamente diverso in C#, rispetto ai normali termini OO. –

+2

Oh sì, hai ragione. Nei miei termini questo è tutto enumerato e ho completamente dimenticato che C# chiama questo pattern iteratore. –

2

L'enumerazione riguarda gli oggetti mentre l'iterazione riguarda solo i valori. L'enumerazione viene usata quando usiamo l'hash del vettore ecc. Mentre l'iterazione è usata nel ciclo while per il loop, ecc. Non ho mai usato la parola chiave yield, quindi non potrei dirlo.

+0

Questo può essere vero ma solo per dot net. In alcune lingue è possibile iterare oggetti/valori e enumerare oggetti/valori –

+0

Beh, io sono un programmatore .NET. Scusate per la mia ignoranza, è solo il modo in cui ho imparato come funzionavano. – Kredns

3

"Gli iteratori sono una nuova funzionalità in C# 2.0. Un iteratore è un metodo, ottiene accessor o operatore che consente di supportare l'iterazione in una classe o in una struttura senza dover implementare l'intera interfaccia IEnumerable. un iteratore, che attraversa semplicemente le strutture dati della classe: quando il compilatore rileva il tuo iteratore, genererà automaticamente i metodi Current, MoveNext e Dispose dell'interfaccia IEnumerable o IEnumerable. " - msdn

41

In C# 2+, iterators sono un modo per il compilatore di generare automaticamente le interfacce IEnumerable e/o IEnumerable <T>.

Senza iteratori, è necessario creare una classe che implementa IEnumerator, inclusi Current, MoveNext e Reset. Ciò richiede una buona quantità di lavoro. Normalmente, dovresti creare una classe privata che IEnumerator implemtented <T> per il tuo tipo, quindi yourClass.GetEnumerator() dovrebbe costruire quella classe privata e restituirla.

Gli iteratori sono un modo per il compilatore di generare automaticamente questo per voi, usando una semplice sintassi (resa). Ciò consente di implementare GetEnumerator() direttamente nella classe, senza che una seconda classe (The IEnumerator) venga specificata dall'utente. La costruzione di quella classe, con tutti i suoi membri, è fatta per te.

Gli iteratori sono molto intuitivi per gli sviluppatori: le operazioni vengono eseguite in modo molto efficiente, con uno sforzo molto minore.

Quando si utilizza foreach, i due si comportano in modo identico (a condizione di scrivere correttamente il proprio IEnumerator personalizzato). Iteratori rendono la vita molto più semplice.

12

Per comprendere gli iteratori, dobbiamo prima capire gli enumeratori.

Gli enumeratori sono oggetti speciali che forniscono uno strumento per spostarsi attraverso una lista ordinata di elementi uno alla volta (lo stesso tipo di cosa viene talvolta chiamato "cursore"). Il framework .NET fornisce due importanti interfacce relative agli enumeratori: IEnumerator e IEnumerable. Gli oggetti che implementano IEnumerator sono essi stessi degli enumeratori; supportano i seguenti componenti:

  • l'attuale struttura, che indica una posizione nella lista

  • il metodo MoveNext, che sposta l'elemento corrente uno lungo l'elenco

  • il metodo Ripristina, che sposta l'oggetto corrente nella sua posizione iniziale (che è prima del primo elemento).

D'altro canto, Iterаtors implementa il dispositivo di identificazione. .NET 2.0 ha introdotto l'iteratore, che è un enumeratore manifestato dal compilatore. Quando l'oggetto enumerabile consente a GetEnumertor, direttamente o indirettamente, il compilatore genera e restituisce un oggetto iteratore di tipo inappropriato. Opzionalmente, l'iteratore può essere un oggetto enumerato e enumeratore combinato.

L'ingrediente essenziale di un blocco iteratore è lo stadio di rendimento. C'è una grande differenza tra iteratori ed enumeratori: Iterators non implementano il metodo di Reset. La modifica del metodo di ripristino su un iteratore causa un'eccezione.

Il punto degli iteratori è consentire la facile implementazione degli enumeratori. Quando un metodo deve restituire un enumeratore o una classe enumerabile per un elenco ordinato di elementi, viene scritto in modo tale da restituire ciascun elemento nell'ordine corretto utilizzando l'istruzione 'yield'.

16

Cosa # C chiama un iteratore è più comunemente (al di fuori del mondo C#) chiamato un generator o funzione generatore (ad esempio in Python). Una funzione di generatore è un caso specializzato di coroutine. Un C# iterator (generatore) è una forma speciale di un enumeratore (un tipo di dati che implementa l'interfaccia IEnumerable).

Non mi piace questo utilizzo del termine iteratore per un generatore C# perché è tanto un enumeratore quanto un iteratore. Troppo tardi, però, Microsoft ha cambiato idea.

Per contrasto, considerare che in C++ un iteratore è un valore utilizzato principalmente per accedere a elementi sequenziali in una raccolta. Può essere avanzato, derferenced per recuperare un valore e testato per vedere se è stata raggiunta la fine della collezione.

+2

Bene, è la migliore risposta qui;) – mrzepa

7

Poiché non sono stati forniti esempi, eccone uno che mi è stato utile.

Un enumeratore è un oggetto che si ottiene quando si chiama .GetEnumerator() su una classe o un tipo che implementa l'interfaccia IEnumerator. Quando viene implementata questa interfaccia, è stato creato tutto il codice necessario per il compilatore per consentire all'utente di utilizzare foreach in "iterazione" sulla raccolta.

Non ottenere la parola "iterazione" confusa con l'iteratore: sia l'enumeratore che l'iteratore consentono di "iterare". Enumerare e iterare sono fondamentalmente lo stesso processo, ma sono implementati in modo diverso. impiantato l'interfaccia IEnumerator. Iterating significa che hai creato il costrutto iteratore nella tua classe (illustrato di seguito) e chiami foreach sulla classe, momento in cui il compilatore crea automaticamente la funzionalità di enumerazione per te.

Nota anche che non devi fare lo squat con il tuo enumeratore. Puoi chiamare lo MyClass.GetEnumerator() tutto il giorno e non fare nulla con esso (esempio:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator()).

Nota anche che il tuo costrutto iteratore nella tua classe viene solo realmente utilizzato quando lo stai effettivamente utilizzando, ovvero hai chiamato foreach nella tua classe.

Ecco un esempio iteratore da msdn:

public class DaysOfTheWeek : System.Collections.IEnumerable 
{ 

    string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" }; 

    //This is the iterator!!! 
    public System.Collections.IEnumerator GetEnumerator() 
    { 
     for (int i = 0; i < days.Length; i++) 
     { 
      yield return days[i]; 
     } 
    } 

} 

class TestDaysOfTheWeek 
{ 
    static void Main() 
    { 
     // Create an instance of the collection class 
     DaysOfTheWeek week = new DaysOfTheWeek(); 

     // Iterate with foreach - this is using the iterator!!! When the compiler 
     //detects your iterator, it will automatically generate the Current, 
     //MoveNext and Dispose methods of the IEnumerator or IEnumerator<T> interface 
     foreach (string day in week) 
     { 
      System.Console.Write(day + " "); 
     } 
    } 
} 
// Output: Sun Mon Tue Wed Thr Fri Sat 
9

"Mentre una dichiarazione foreach è il consumatore del enumeratore, un iteratore è il produttore del enumeratore."

Quanto sopra è come "C# 5.0 In A NutShell" lo spiega, ed è stato utile per me.

In altre parole, l'istruzione foreach utilizza MoveNext() e la proprietà Current dell'IEnumerator per scorrere una sequenza, mentre l'iteratore viene utilizzato per produrre l'implementazione dell'IEnumerator che verrà utilizzata dall'istruzione foreach. In C#, quando scrivi un metodo iteratore contenente un'istruzione yield, il compilatore genererà per te un enumeratore privato. E quando iterate attraverso gli elementi nella sequenza, chiamerà la proprietà MoveNext() e Current dell'enumeratore privato. Questi metodi/proprietà sono implementati dal codice nel metodo iteratore che sarà chiamato ripetutamente per produrre valori fino a quando non ci saranno valori da produrre.

Questa è la mia comprensione di come C# definisce gli enumeratori e gli iteratori.

+0

Questa frase lo riassume molto succintamente. Peccato che questa risposta sia finita, abbia il mio +1! – AnorZaken

Problemi correlati