2010-02-19 6 views

risposta

12

Si potrebbe esporlo come un IEnumerable<T>, ma non solo di tornare direttamente:

public IEnumerable<object> Objects { get { return obs.Select(o => o); } } 

Dal momento che hai indicato che si voleva solo attraversamento della lista, questo è tutto ciò che serve.

Si potrebbe essere tentati di restituire il List<object> direttamente come IEnumerable<T>, ma sarebbe errato, in quanto si potrebbe facilmente controllare l'IEnumerable<T> in fase di esecuzione, determinare è un List<T> e gettarlo ai quali e mutare il contenuto.

Tuttavia, utilizzando return obs.Select(o => o); si finisce per restituire un iteratore su List<object>, non un riferimento diretto allo stesso List<object>.

Alcuni potrebbero pensare che questo si qualifica come "espressione degenere" in base alla sezione 7.15.2.5 della specifica del linguaggio C#. Tuttavia, Eric Lippert goes into detail as to why this projection isn't optimized away.

Inoltre, le persone suggeriscono che si usi AsEnumerable extension method. Questo non è corretto, poiché l'identità di riferimento dell'elenco originale viene mantenuta. Dalla sezione Osservazioni della documentazione:

Procedimento AsEnumerable<TSource>(IEnumerable<TSource>) ha alcun effetto se non per cambiare la fase di compilazione di origine da un tipo che implementa IEnumerable<T> a IEnumerable<T> stessa.

In altre parole, tutto ciò che fa è gettata il parametro sorgente per IEnumerable<T>, che non aiuta a proteggere l'integrità referenziale, viene restituito il riferimento originario e possono essere gettati di nuovo a List<T> e essere utilizzato per mutare la lista.

+2

Nota che non ottimizzeremo mai una chiamata * esplicita * a Seleziona se è presente nel codice. Ottimizziamo la chiamata implicita a Seleziona quando trasformi un'espressione di query in chiamate di metodo. Se dici "da x in y dove b seleziona x" non c'è Seleziona, solo una Dove. Ma se dici "da x in y seleziona x" allora non generiamo solo "y", generiamo una chiamata select su di esso per garantire l'immutabilità del risultato. La risposta –

0

Avete considerato di derivare una classe da System.Collections.ReadOnlyCollectionBase?

11

È possibile utilizzare uno ReadOnlyCollection o effettuare una copia dello List e restituirlo invece (considerando la penalità delle prestazioni dell'operazione di copia). Puoi anche usare List<T>.AsReadOnly.

+0

è incompleta. codice per favore –

1

esporre un ReadOnlyCollection<T>

+0

come? risposta scadente –

+1

Non è esattamente un problema fare in modo che l'intervistatore cerchi un po 'di caccia. Il primo risultato su Google rende ovvio come esporre un 'ReadOnlyCollection '. – user7116

+0

sixlettervariables si perde ovviamente il punto del sito. –

2

È possibile farlo in due modi:

  1. sia per la conversione della lista in una collezione in sola lettura:

    new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs) 
    
  2. O restituendo un IEnumerable di gli articoli:

    this.obs.AsEnumerable() 
    
2

alla vostra interfaccia di aggiungere il metodo seguente firma: pubblico IEnumerable TraverseTheList()

implimented come così:

public IEnumerable<object> TraverseTheList() 
{ 

    foreach(object item in obj) 
    { 
     yield return item; 
    } 


} 

che vi permetterà di effettuare le seguenti operazioni:

foreach(object item in Something.TraverseTheList()) 
{ 
// do something to the item 
} 

Il rendimento yield indica al compilatore di creare un enumeratore per te.

+0

un angolo diverso; eccellente. –

3

Questo è già stato detto, ma non vedo nessuna delle risposte come superclear.

Il modo più semplice è quello di restituire semplicemente un ReadOnlyCollection

private List<object> objs; 

public ReadOnlyCollection<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

Lo svantaggio di questo è che, se si desidera modificare l'implementazione in seguito, quindi alcuni chiamanti potrebbero già essere dipendente dal fatto, che la la raccolta fornisce l'accesso casuale. Quindi, una definizione più sicuro sarebbe quello di esporre solo un IEnumerable

public IEnumerable<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

Si noti che non c'è bisogno di chiamare AsReadOnly() per compilare il codice. Ma se non lo fai, il chiamante mi limita a restituire il valore restituito a un elenco e a modificare l'elenco.

// Bad caller code 
var objs = YourClass.Objs; 
var list = objs as List<object>; 
list.Add(new object); // They have just modified your list. 

Lo stesso potenziale problema esiste anche con questa soluzione

public IEnumerable<object> Objs { 
    get { 
     return objs.AsEnumerable(); 
    } 
} 

Quindi senz'altro consiglio che si chiama AsReadOnly() su di voi la lista, e restituire tale valore.

+0

ottima combinazione di semplice + sicuro. –

Problemi correlati