как мне обращаться с нулевыми списками как с пустыми списками в linq? - PullRequest
7 голосов
/ 04 февраля 2010

Ниже приведен тестовый код linqpad. Когда он запускается, это приводит к ошибкам, потому что второй экземпляр «item» имеет пустой список подэлементов, а не пустой список.

Я хочу, чтобы обе ситуации (нулевой или пустой список) обрабатывались одинаково, но мне было интересно, есть ли более понятный способ, чем просто поставить нулевую проверку в списке и инициализировать пустой список при наличии нуля.

другими словами, я мог бы сделать это:

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

но это немного уродливо, и я удивляюсь, как я могу улучшить это?

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

в качестве дополнительного вопроса, может ли этот же запрос linq быть представлен как лямбда и обрабатывать нули одинаково?

Ура, Крис

Ответы [ 4 ]

14 голосов
/ 04 февраля 2010

Вы можете использовать оператор объединения нулей

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

Но я думаю, вы должны просто отфильтровать пустые

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

Что касается лямбда-версии, можно сказать

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

Но версия синтаксиса запроса намного удобнее для чтения.

11 голосов
/ 04 февраля 2010
from si in (i.subitems ?? new List<item>())

как насчет этого?

9 голосов
/ 04 февраля 2010

Вы можете добавить (злой) метод расширения, чтобы сделать всю работу за вас

public static IEnumerable<T> EnsureNotEmpty<T>(this IEnumerable<T> enumerable) {
  if ( enumerable == null ) {
    return Enumerable.Empty<T>();
  } else { 
    return enumerable;
  }
}
0 голосов
/ 04 февраля 2010

Дополнительным методом было бы не допустить, чтобы подэлементы были нулевыми. Вы можете сделать конструктор элемента так, чтобы по умолчанию для подэлемента использовался пустой список, а затем не разрешать нулевое значение в установщике подэлементов.

Это, конечно, предполагает, что у вас есть доступ для изменения элемента.

Нулевой оператор объединения - это то, что вы ищете, как указал Хантер Дейли

...