【问题标题】:how do I treat null lists like empty lists in linq?如何将空列表视为 linq 中的空列表?
【发布时间】:2011-01-13 04:47:32
【问题描述】:

下面是一些 linqpad 测试代码。当它运行时会出错,因为“item”的第二个实例有一个空的子项目列表,而不是一个空列表。

我想以完全相同的方式处理这两种情况(null 或空列表),但我想知道是否有比仅对列表进行空检查并在有空时初始化空列表更简洁的方法。

换句话说,我可以这样做:

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 查询是否可以表示为 lambda 并以相同的方式处理空值?

干杯,克里斯

【问题讨论】:

    标签: c# .net linq null-coalescing-operator


    【解决方案1】:

    您可以使用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();
    

    但我认为你应该只过滤掉空的

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

    至于你可以说的 lambda 版本

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

    但是查询语法版本更易读。

    【讨论】:

    • 实际上第二个选项可读性很强,并不意味着只需要创建一个新列表就可以忽略。谢谢
    • @Chris Simpson:我添加了 lambda 版本,因为你要求它。查询语法版本更具可读性。
    • 我真的认为 where 子句是这里最干净的解决方案,所以我将其标记为答案。我只是对等效的 lambda 感到好奇,但我同意,它不那么可读。谢谢。
    【解决方案2】:
    from si in (i.subitems ?? new List<item>())
    

    怎么样?

    【讨论】:

    【解决方案3】:

    您可以添加一个(邪恶的)扩展方法来为您完成工作

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

    【讨论】:

    • Enumerable.Repeat&lt;T&gt;(0)Enumerable.Empty&lt;T&gt;() 更可取吗?
    • @bdukes,Enumerable.Empty 更好,因为它更能说明您的意图。出于某种原因,尽管我一直忘记它是框架的一部分,而是改为执行 Repeat(0)。
    • 该方法应该被称为EnsureNotNull(...)。因为EnsureNotEmpty(...) 听起来像是会添加一个故意的项目。 :->
    • 为什么说这是邪恶的?我很喜欢这种方法。
    【解决方案4】:

    另一种方法是不允许子项为空。您可以创建项目构造函数,使其默认子项为空列表,然后在子项设置器中不允许为 null。

    这当然假设您有权修改项目。

    正如 Hunter Daley 所指出的,您正在寻找空合并运算符

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多