2010-10-08 5 views
29

Qual è il modo standard per ottenere un elenco digitato, a sola lettura, vuoto in C# o ce n'è uno?C#/.NET equivalente per le raccolte Java. <T> emptyList()?

ETA: Per chi chiede "perché?": Ho un metodo virtuale che restituisce un IList (o meglio, post-risposte, un IEnumerable), e l'implementazione di default è vuoto. Qualunque cosa ritorni sulla lista dovrebbe essere di sola lettura perché scrivere su di essa sarebbe un bug, e se qualcuno ci prova, voglio fermarmi e prendere fuoco immediatamente, piuttosto che aspettare che il bug si mostri in qualche modo in un secondo momento.

+4

Cosa farai con una lista in sola lettura vuoto Comunque? Solo curioso. – goenning

+0

Sto indovinando un 'IEnumerable ' vuoto è probabilmente la risposta giusta qui - è un IList davvero necessario? o solo una raccolta vuota di sola lettura? –

+1

solo curioso, perché hai bisogno di una lista di sola lettura vuota? –

risposta

18

Personalmente, credo che questo è meglio di qualsiasi delle altre risposte:

static readonly IList<T> EmptyList = new T[0]; 
  • Array implementano IList<T>.
  • Non è possibile aggiungere a un array.
  • Non è possibile assegnare a un elemento in un array vuoto (perché lo è nessuno).
  • Questo è, a mio avviso, molto più semplice di new List<T>().AsReadOnly().
  • È ancora possibile restituire un IList<T> (se lo si desidera).

Per inciso, questo è quello che Enumerable.Empty<T>() utilizza effettivamente sotto il cofano, se ricordo correttamente. Quindi in teoria potresti anche fare (IList<T>)Enumerable.Empty<T>() (anche se non vedo alcuna ragione per farlo).

+0

La tua risposta ha davvero senso solo per me in termini di commenti allegati alla [risposta di Virtlink] (https://stackoverflow.com/a/10659068/712526). – jpaugh

+1

Dal momento che 4.6 non è nemmeno necessario fornire più il proprio oggetto, è sufficiente restituire Array.Empty (). – ZunTzu

21

Si può solo creare un elenco:

List<MyType> list = new List<MyType>(); 

Se si desidera un vuoto IEnumerable<T>, utilizzare Enumerable.Empty<T>():

IEnumerable<MyType> collection = Enumerable.Empty<MyType>(); 

Se veramente si vuole un lista di sola lettura, si potrebbe fare:

IList<MyType> readonlyList = (new List<MyType>()).AsReadOnly(); 

Questo restituisce un ReadOnlyCollection<T>, che implementa IList<T>.

+2

Ho pensato anche a questo, ma poi ho visto il requisito di sola lettura. Poi ho pensato a quale sarebbe stato il punto di un elenco di sola lettura vuoto . Cosa mi manca? –

+0

'Non c'è una lista' '... –

+0

@Jay: Ho aggiunto anche questa opzione ... –

7
IList<T> list = new List<T>().AsReadOnly(); 

Oppure, se si vuole un IEnumerable<>:

IEnumerable<T> sequence = Enumerable.Empty<T>(); 
+1

Dal 4.6 esiste una soluzione migliore: IList list = Array.Empty (); – ZunTzu

-1

Che dire:

readonly List<T> mylist = new List<T>(); 

Non certo perché si vuole che in sola lettura; questo non ha molto senso nella maggior parte degli scenari che riesco a pensare, però.

+2

Inoltre, questo non rende l'elenco di sola lettura. – Timwi

+0

Ri: perché, vedere la domanda modificata sopra. –

4

Se si desidera un elenco il cui contenuto non può essere modificato, si può fare:

ReadOnlyCollection<Foo> foos = new List<Foo>().AsReadOnly(); 
2

Per espandere su Dan Tao's answer, la seguente implementazione può essere utilizzata allo stesso modo di Enumerable.Empty<T>(), specificando invece List.Empty<T>().

public static class List 
{ 
    public static IList<T> Empty<T>() 
    { 
     // Note that the static type is only instantiated when 
     // it is needed, and only then is the T[0] object created, once. 
     return EmptyArray<T>.Instance; 
    } 

    private sealed class EmptyArray<T> 
    { 
     public static readonly T[] Instance = new T[0]; 
    } 
} 

Edit: ho cambiare il codice di cui sopra in modo da riflettere il risultato di una discussione con Dan Tao circa pigri contro l'inizializzazione desiderosi del campo Instance.

+0

Inizializzazione pigra di un array di lunghezza zero? Personalmente ritengo che sia un errore, poiché aggiunge complessità, renderà le prestazioni leggermente peggiori (chiamata di metodo extra su ogni accesso), ha una condizione di competizione (due thread che chiamano 'List.Empty ()' potrebbero ottenere contemporaneamente oggetti diversi) e non ti compra quasi nulla (come pensi che il costo di inizializzazione di un singolo array a lunghezza zero sia paragonabile a quello di JIT che compila una nuova classe?). Vai con un campo pubblico 'static readonly' inizializzato, o - se la tua coscienza non lo consente - un campo privato più il metodo' Empty'. Solo i miei due centesimi! –

+1

Due thread che ottengono oggetti diversi non è un problema. Le prestazioni non sono influenzate dal momento che la chiamata è [molto probabilmente inline] (https://blogs.msdn.com/b/ericgu/archive/2004/01/29/64717.aspx). Non vedo come una linea di logica effettiva possa seriamente aggiungere alla complessità. E ultimo ma non meno importante: ho appena controllato l'implementazione di 'Enumerable.Empty ()' ed è molto simile a quello che ho scritto.Se si ha bisogno di liste vuote di tutti i tipi dappertutto, utilizzare questo approccio poiché salva allocazioni e spazzatura. Se uno solo raramente ha bisogno di una lista vuota, usa il tuo 'statico readonly'. – Virtlink

+0

Probabilmente hai ragione ad essere sulla difensiva, dato che il mio commento stava certamente dividendo i capelli. Tuttavia, diversi oggetti potrebbero essere un problema se, ad esempio, si avesse un codice critico che dipendeva dal controllo 'if (list == List.Empty ())'. Inoltre, in che modo questo approccio risparmia su allocazioni e spazzatura? –

6

Partendo .net 4.6 è anche possibile utilizzare:

IList<T> emptyList = Array.Empty<T>(); 

Questo non solo creare una nuova istanza una volta per ogni diverso tipo specificato come T.

+0

Proprio come String.Empty, che fa sempre riferimento alla stessa istanza anziché creare una nuova stringa vuota. –

+0

@David De Sloovere la stringa vuota letterale "" fa anche riferimento alla stessa istanza grazie all'internamento delle stringhe (solo per i lettori che si sentirebbero obbligati a sostituire "" con String.Empty). – ZunTzu