2010-02-04 14 views
5

Di seguito è riportato un codice di prova per linqpad. Quando viene eseguito questo errore, la seconda istanza di "elemento" ha un elenco nullo di elementi secondari rispetto a un elenco vuoto.Come si gestiscono gli elenchi Null come elenchi vuoti in linq?

Voglio trattare entrambe le situazioni (elenco nullo o vuoto) esattamente nello stesso modo, ma mi chiedevo se c'era un modo più pulito di mettere semplicemente un controllo Null sulla lista e inizializzare una lista vuota quando c'è un null.

in altre parole, avrei potuto fare questo:

from si in (i.subitems == null ? new List<item>() : i.subitems) 

ma questo è un po 'brutto e mi chiedevo come avrei potuto migliorare su questo?

public class item 
{ 
    public string itemname { get; set; } 
    public List<item> subitems { get; set; } 
} 

void Main() 
{ 
    List<item> myItemList = new List<item>() 
    { 
     new item 
     { 
      itemname = "item1", 
      subitems = new List<item>() 
      { 
       new item { itemname = "subitem1" }, 
       new item { itemname = "subitem2" } 
      } 
     }, 
     new item 
     { 
      itemname = "item2" 
     } 
    }; 

    myItemList.Dump(); 

    var res = (from i in myItemList 
      from si in i.subitems 
      select new {i.itemname, subitemname = si.itemname}).ToList(); 

    res.Dump(); 
} 

come una questione bonus, può questa stessa query LINQ essere rappresentato come un lambda e trattare i null allo stesso modo?

Cheers, Chris

risposta

13

È possibile utilizzare il null coalescing operator

var res = (from i in myItemList 
      from si in i.subitems ?? new List<item>() 
      select new { i.itemname, subitemname = si.itemname }).ToList(); 

Ma penso che si dovrebbe solo filtrare i vuoti fuori

var res = (from i in myItemList 
      where i.subitems != null 
      from si in i.subitems 
      select new { i.itemname, subitemname = si.itemname }).ToList(); 

Come per una versione lambda si potrebbe dire

var res = myItemList.Where(x => x.subitems != null) 
        .SelectMany(
         x => x.subitems.Select(
          y => new { x.itemname, subitemname = y.itemname } 
         ) 
        ); 

Ma la versione della sintassi della query è molto più leggibile.

+0

in realtà quella seconda opzione è molto leggibile e non significa che una nuova lista deve essere creata solo per essere ignorata. grazie –

+0

@ Chris Simpson: ho aggiunto la versione lambda da quando l'hai richiesta.La versione della sintassi della query è molto più leggibile. – jason

+1

Penso davvero che la clausola where sia la soluzione più pulita qui, quindi segnalo come risposta. Ero solo curioso sull'equivalente lambda ma sono d'accordo, non è così leggibile. Grazie. –

11
from si in (i.subitems ?? new List<item>()) 

Che ne dici?

+1

sì, è migliore del mio (e mi sto a calci per non fare che, in primo luogo), ma significa continuando a creare un oggetto semplicemente per eliminarlo, cosa che non va bene –

+0

Punti bonus per trovare un buon uso per ?? – captncraig

+0

@captncraig Per altri usi di ??, vedere http://stackoverflow.com/questions/1689530/how-useful-is-cs-operator/1689544#1689544 –

8

Si potrebbe aggiungere una (male) metodo di estensione per fare il lavoro per voi

public static IEnumerable<T> EnsureNotEmpty<T>(this IEnumerable<T> enumerable) { 
    if (enumerable == null) { 
    return Enumerable.Empty<T>(); 
    } else { 
    return enumerable; 
    } 
} 
+0

È 'Enumerable.Repeat (0)' preferibile a ' Enumerable.Empty () '? – bdukes

+0

@bdukes, Enumerable.Empty è migliore in quanto è più dichiarativo della tua intenzione. Per qualche ragione però continuo a dimenticare che è una parte del framework e invece di Repeat (0). – JaredPar

+4

Il metodo dovrebbe essere chiamato 'EnsureNotNull (...)'. Perché 'ConfirmNotEmpty (...) 'sembra che aggiungerebbe un elemento deliberato. : -> – herzmeister

0

Un metodo addizionale non è quello di consentire che i valori secondari siano nulli. È possibile creare il costruttore dell'elemento in modo che assuma automaticamente un elemento secondario in una lista vuota e quindi non consentire il null nel subitem setter.

Questo ovviamente presuppone che si abbia accesso a modificare l'elemento.

L'operatore null coalescenza è quello che stai cercando, come sottolineato da Hunter Daley

Problemi correlati