2010-02-04 11 views
5

A continuación se muestra un código de prueba de linqpad. Cuando esto se ejecuta errores, porque la segunda instancia de "elemento" tiene una lista nula de subelementos en lugar de una lista vacía.¿cómo trato las listas nulas como listas vacías en linq?

Quiero tratar ambas situaciones (lista vacía o nula) exactamente de la misma manera, pero me preguntaba si había una manera más limpia que simplemente poner una verificación nula en la lista e inicializar una lista vacía cuando hay un nulo.

en otras palabras, que podría hacer esto:

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

pero eso es un poco feo y me preguntaba cómo podría mejorar en eso?

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(); 
} 

como una pregunta extra, puede esta misma consulta LINQ puede representar como un lambda y tratar los nulos de la misma manera?

Saludos, Chris

Respuesta

13

Se podría utilizar el 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(); 

Pero creo que sólo debe filtrar las vacías a cabo

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

En cuanto a una versión lambda, podría decir

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

Pero la versión de sintaxis de la consulta es mucho más leíble.

+0

en realidad esa segunda opción es muy legible y no significa que una nueva lista debe crearse solo para ser ignorada. gracias –

+0

@Chris Simpson: agregué la versión de lambda desde que la solicitó.La versión de sintaxis de consulta es mucho más legible. – jason

+1

Realmente creo que la cláusula where es la solución más limpia aquí, así que estoy marcando esto como la respuesta. Solo tenía curiosidad sobre el equivalente lambda, pero estoy de acuerdo, no es tan legible. Gracias. –

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

¿qué tal?

+1

sí, eso es mejor que la mía (y estoy bebiendo yo para no hacer que, en primer lugar), pero todavía significa crear un objeto simplemente para eliminarlo que se siente mal –

+0

Puntos de bonificación para encontrar un buen uso para ?? – captncraig

+0

@captncraig Para otros usos de ??, vea http://stackoverflow.com/questions/1689530/how-useful-is-cs-operator/1689544#1689544 –

8

Se podría añadir un (mal) método de extensión para hacer el trabajo para usted

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

Es 'Enumerable.Repeat (0)' preferible a ' Enumerable.Empty () '? – bdukes

+0

@bdukes, Enumerable.Empty es mejor ya que es más declarativo de su intención. Por alguna razón, sigo olvidando que es una parte del framework y hago Repeat (0) en su lugar. – JaredPar

+4

El método debe llamarse 'EnsureNotNull (...)'. Porque 'EnsureNotEmpty (...)' suena como si agregara un elemento deliberado. : -> – herzmeister

0

Un método adicional sería no permitir que los subelementos sean nulos. Puede hacer que el constructor del elemento establezca de manera predeterminada el subelemento en una lista vacía y luego no permita el nulo en el establecedor de subtemas.

Por supuesto, se supone que tiene acceso para modificar el elemento.

El operador coalescente nula es lo que busca como se ha señalado por Hunter Daley

Cuestiones relacionadas