2010-12-28 11 views
7

Uso il seguente codice per consentire a myClass di utilizzare foreach. Ma sono piuttosto nuovo alla programmazione e ho qualche difficoltà a comprendere il seguente codice. Ho descritto i miei problemi nei commenti. Sarei grato di fornire alcune informazioni.Domanda relativa a IEnumerable e IEnumerator

public class MyClass : IEnumerable<string> 
    { 
    //1) What is IEnumerator for? 
     // Whats the difference between IEnumerator and IEnumerable 
    public IEnumerator<string> GetEnumerator()  
    { 
      yield return "first";   
      yield return "second";  
    }  
    //2) What is it for? It just calls above method 
    IEnumerator IEnumerable.GetEnumerator() 
     { 
      return GetEnumerator(); 
     } 
    } 
    //3) Lastly what benefits I have from implementing genetic interface 
    //IEnumerable<string> instead of just IEnumerable 
+3

Lascerò che John Skeet risponda a questo –

+4

@Hasan: ho paura di quello che ti farà, scrivendo male il suo nome. – JYelton

risposta

11

Qual è la differenza tra IEnumerator e IEnumerable?

La risposta di Jason è buona, ma ho pensato di aggiungere solo il modo in cui penso a questo. Immaginate di avere una sequenza:

1, 1, 2, 3, 5, 8, 13, ... 

Ora immaginate di avere una freccia che punta in una qualche posizione di tale sequenza:

1, 1, 2, 3, 5, 8, 13, ... 
     ^

Una "freccia" è un oggetto che può fare due cose. In primo luogo, può darti la cosa a cui punta. In secondo luogo, può fare riferimento alla prossima cosa.

IEnumerator è una freccia. Ha una proprietà, Current, che ti dà la cosa a cui punta. Ha un metodo, MoveNext() che si fa punto alla prossima cosa.

Come si ottiene una freccia in primo luogo? Hai bisogno di una fabbrica di frecce. Chiedete alla fabbrica una freccia e vi darà una freccia che punta al primo elemento della sequenza.

IEnumerable è una fabbrica di frecce. Ha un metodo, GetEnumerator, che ti dà una freccia per il primo elemento della sequenza.

Una bella proprietà di questo schema è che è possibile avere più frecce che puntano a punti diversi nella stessa sequenza.

quali sono i vantaggi dell'implementazione di un'interfaccia generica IEnumerable anziché solo IEnumerable?

Supponiamo che la sequenza sia di numeri interi. Se si implementa IEnumerable poi quando dici

foreach(int x in mysequence) 

ciò che realmente fare è convertire l'int nella sequenza di opporsi, boxe il numero intero, e poi Unbox immediatamente l'oggetto di nuovo al numero intero, l'aggiunta di un'allocazione di memoria completamente inutile ad ogni singola operazione. Se il compilatore sa che la sequenza è di interi, può saltare l'operazione di boxe non necessaria.

Supponiamo che la sequenza sia di stringhe. Se si implementa IEnumerable<string> allora si può dire:

string first = mysequence.First(); 

Se non lo fai, allora dovete dire

string first = (string)mysequence.First(); 

che è inutile e soggetto a errori. Piuttosto che istruire il compilatore tramite un cast che il tipo è stringa, è possibile semplicemente garantire che il tipo sia stringa utilizzando il sistema di tipi.

+2

Bella metafora con il concetto di freccia. Può anche valere la pena menzionare che un comune effetto collaterale di questo modello è che l'alterazione della collezione inizia enumerata generalmente invalida tutte le "frecce" che puntano in essa. – LBushkin

+0

Nota secondaria su _ "GetEnumerator, che fornisce una freccia al primo elemento della sequenza" _: in base a [MSDN] (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable .getenumerator (v = vs.110) .aspx), ti dà una freccia che punta ad una cosa non definita _prima_ la prima cosa. – jan

+0

@jan: buon punto! –

0

GetEnumerator è stato intorno dal prima generici sono stati introdotti alla lingua, in modo da non rompere preesistente codice, il metodo predefinito chiama attraverso l'implementazione generica.

Con un'enumerazione generica, il consumatore della classe non ha bisogno di trasmettere ogni elemento alla stringa durante l'iterazione.

6

1) Che cos'è lo IEnumerator? Qual è la differenza tra IEnumerator e IEnumerable?

IEnumerator è un'interfaccia che rappresenta i metodi che consentono di enumerare una sequenza. La differenza tra IEnumerator e IEnumerable è che il primo rappresenta il contratto per oggetti che consentono di enumerare una sequenza e il secondo rappresenta il contratto per gli oggetti che sono una sequenza su cui è possibile eseguire l'enumerazione.

public IEnumerator<string> GetEnumerator() { 
     yield return "first";   
     yield return "second";  
}  


IEnumerator IEnumerable.GetEnumerator() { 
    return GetEnumerator(); 
} 

2) Che cosa serve? Si chiama solo metodo sopra.

Il primo rappresenta un'implementazione del metodo GetEnumerator sul contratto IEnumerable<string>. Quest'ultimo rappresenta un'implementazione esplicita del metodo GetEnumerator sul contratto IEnumerable. Il problema è che entrambi i contratti hanno un metodo denominato GetEnumerator ma con diversi tipi di resi in modo che un metodo non possa soddisfare contemporaneamente entrambi i contratti (qualsiasi classe che implementa IEnumerable<T> deve anche implementare IEnumerable come IEnumerable<T> : IEnumerable). Quest'ultimo richiama l'implementazione di IEnumerable<string>.GetEnumerator in quanto è un'implementazione ragionevole che restituisce un IEnumerator come IEnumerator<string> : IEnumerator.

3) Infine, quali vantaggi ho dall'implementazione dell'interfaccia generica IEnumerable<string> anziché solo IEnumerable?

Forte tipizzazione. Sai che gli elementi di una sequenza IEnumerable<string> sono tutte le istanze di String mentre non lo sai per IEnumerable e potresti finire per provare a trasmettere un elemento di quest'ultima a un'istanza di String quando non può essere.

3

1) A cosa serve IEnumerator?

IEnumerator è la parte di lavoro reale con i membri MoveNext() e Current.

cosa è la differenza tra IEnumerator e IEnumerable

IEnumerable è l'interfaccia per una collezione per segnalare che ha un GetEnumerator().

2) [GetEnumerator non generico] A cosa serve? Chiama sopra il metodo

Il metodo non generico è solo lì per compatibilità con le versioni precedenti. Si noti che viene spostato "fuori dalla vista" il più possibile utilizzando l'implementazione esplicita. Implementalo perché devi e poi dimenticarlo.

3) Infine quali benefici ho da attuare interfaccia genetica IEnumerable invece di IEnumerable

Quando utilizzato con il foreach adavantage è piccolo, come foreach scriverà pressofuso la variabile loop. Essa vi permetterà di utilizzare var nel foreach:

foreach (var s in myClassInstance)  // needs `IEnumerable<string>` 
foreach (string s in myClassInstance) // works with `IEnumerable` as well 

Ma con IEnumerable<string> hai anche un'interfaccia di tipo-safe ad altre aree, in particolare LINQ:

MyClass mc = new MyClass(); 
string s = mc.FirstOrDefault(); 
3

Questa è la dichiarazione per IEnumerable<T>:

public interface IEnumerable<out T> : IEnumerable 
{ 
    IEnumerator<T> GetEnumerator(); 
} 

non hai scelta, si avere per implementare il non generico IE interfaccia numerabile pure. Otterrai un errore di compilazione se ometti l'implementazione IEnumerable.GetEnumerator(). Si tratta di un bagaglio rimasto dai giorni di .NET 1.x in cui i generici non erano ancora disponibili e il periodo di transizione per .NET 2.0 in cui era necessario supportare l'interoperabilità con gli assembly .NET 1.x. Siamo bloccati con esso.