2012-03-23 15 views
5

In molti dei nostri progetti ho visto alcune raccolte personalizzate o classi di contenitori che contengono una sorta di raccolta generica, ad es. una classe List(of T).Quando utilizzare IEnumerable e GetEnumerator?

Di solito hanno un metodo GetXXX che restituisce un oggetto IEnumerable di qualsiasi tipo utilizzato dalla classe di raccolta personalizzata, in modo che la raccolta interna possa essere iterata utilizzando un ciclo foreach.

ad es.

public IEnumerable<UploadState> GetStates 
{ 
    get 
    { 
     return new List<UploadState>(m_states); 
    } 
} 

La mia domanda è che dovrebbe queste classi anziché implementare l'interfaccia IEnumerable, e chiamare GetEnumerator nella lista stessa.

C'è un modo preferito, o è lo sviluppatore?

+1

Che cos'è il tipo di m_states? Mi chiedo semplicemente perché è racchiuso da 'new List <>' e restituito come 'IEnumerable <>' – sll

+0

http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator.aspx –

risposta

2

Se la classe è una classe di raccolta personalizzata, allora sì, dovrebbe implementare IEnumerable<T>. In questo caso una proprietà pubblica per la lista interna sarebbe ridondante.Immaginate una semplice classe:

public class People : IEnumerable<Person> 
{ 
    List<Person> persons = new List<Person>(); 

    public IEnumerator<Person> GetEnumerator() 
    { 
     return persons.GetEnumerator(); 
    } 
} 

Ma se la classe non può agire come una collezione quindi fornire un IEnumerable proprietà pubblica per i suoi elementi:

public class Flight 
{ 
    List<Person> passengers = new List<Person>(); 

    public IEnumerable<Person> Passengers 
    { 
     get { return passengers; } 
    } 
} 

ogni caso, è sempre allo sviluppatore di scegliere il giusto design.

+0

Grazie Balazs Tihanyi, posso fare una domanda stupida sul tuo esempio, perché hai implementato da IEnumerable e non IEnumberble? Non sono sicuro. – bobbo

+0

Perché vorresti? 'IEnumerable ' è generico e sicuro. 'IEnumerable' è per .NET 1.1 o tipi anonimi. Se implementi solo l'interfaccia 'IEnumerable', dovresti trasmettere gli elementi della lista al loro tipo. –

2

lo farei in questo modo:

public IEnumerable<UploadState> GetStates 
{ 
    get 
    { 
     foreach (var state in m_states) { 
      yield return state; 
     } 
    } 
} 

E 'più pulito, gli utenti non si ottiene una lista in cui non dovrebbero (potrebbero cast a un List<T> dopo tutto) e si don' t necessario creare un oggetto List<T>.

MODIFICA: Ha frainteso la domanda. Penso che se la classe è destinata a essere una raccolta, dovrebbe implementare IEnumerable<T>.

+0

Credo questo non è stato chiesto qui in modo che possa essere un commento non una risposta, ma comunque ha senso dal punto di vista del refactoring – sll

0

Si dovrebbero derivare le classi di raccolta personalizzate in base a una delle classi nello spazio dei nomi System.Collections.ObjectModel. Contengono già le implementazioni di IEnumerable<T> e le interfacce non generiche IEnumerable.

1

Considerare che nell'esempio di codice è stato creato un nuovo elenco . Non so cosa sia m_states, ma se si tratta di una raccolta di tipi di valore, si crea un clone dell'elenco originale. In questo modo la lista di ritorno può essere manipolata dagli elementi Add/Remove/Update del chiamante. senza affettuoso dati originali.

Se m_states sono tipi di riferimento, questo crea ancora un nuova elenco che può essere ancora una volta manipolato dal chiamante Aggiungi/Rimuovi/Nessun elementi di aggiornamento (si tratta di un punto di riferimento!) Senza influenzare i dati originali.

Che dire di IEnumerable<T>, è solo un modo per rendere un tipo di restituzione generico, e non fare un forte abbinamento al tipo List<T>.

+0

m_states è un tipo di riferimento. È dichiarato come Elenco privato m_states = new List (); Ho pensato che il ritorno del metodo non poteva essere manipolato a causa della restituzione di un oggetto IEnumerable , non di un elenco ? – bobbo

+0

@bobbo: certo che ** può **, se si preleva un elemento dalla restituzione della raccolta e si modifica la sua proprietà, si modifica la proprietà dell'elemento ** originale **, poiché questo è un tipo * di riferimento *. – Tigran

+0

OK, questo ha senso. Tuttavia, la tua frase "Se m_states sono tipi di riferimento, questo crea ancora una nuova lista che può essere nuovamente manipolata dal chiamante Aggiungi/Rimuovi/Nessun elemento di aggiornamento (è un riferimento!) Senza influenzare i dati originali." è confuso. Vuoi dire che la nuova lista restituita può essere aggiunta a, e gli elementi possono essere rimossi ma non gli aggiornamenti? Ho pensato che, poiché restituiva ienumerable, puoi modificare gli elementi nell'elenco, cioè modificare una proprietà come hai detto tu, ma non puoi aggiungere e rimuovere elementi nell'elenco. È corretto? – bobbo

0

Penso che se la classe appena implementata si comporta semplicemente come una lista, non è necessario implementarla. Se hai bisogno di qualche tipo di logica personalizzata, dipende da cosa vuoi fare; puoi ereditare l'elenco o implementare IEnumerable. Dipende solo da ciò che deve essere raggiunto.

Problemi correlati