繁体   English   中英

为什么过滤此 IEnumerable 会引发 NullReferenceException?

[英]Why filtering this IEnumerable throws an NullReferenceException?

我有一个似乎无法解决的特殊问题。 我很确定这个错误来自我对 LINQ 查询的工作原理缺乏深入了解

  • 以下服务返回产品列表并且工作正常(没有什么是空的)

    IEnumerable<Product> products = await _productRepository.GetProductList();

    我已经测试了退回的产品,它们的属性(例如,名称、价格、描述)都不是 null。 事实上,我可以将它们展示在桌子上。

  • 但是,如果我尝试过滤返回的产品,我会收到NullReferenceException

IEnumerable<Product> products =products.Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower())).ToList();

即使我检查了属性Name is not null,上面的代码也会抛出NullReferenceException (实际上,没有什么是 null)

如何解决这个问题?

此代码无法编译:

IEnumerable<Product> products = await _productRepository.GetProductList();
IEnumerable<Product> products = products.Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower())).ToList();

所以你需要做一些与你的例子有所不同的事情:

如果你有类似的东西:

IEnumerable<Product> products = await _productRepository.GetProductList()
    .Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower()))
    .ToListAsync();

...那么这应该编译。 此语句中的NullReferenceException可能来自keyword null。

正如上面的评论中提到的,这是一种非常糟糕的取回数据的方式。 问题是,如果您的存储库返回IEnumerable ,它会将所有产品加载到 memory 中,只会让您的消费代码过滤到少数几个。

如果您正在使用单元测试,我建议的存储库模式是让存储库返回IQueryable<TEntity>而不是IEnumerable<TEntity>以便您的消费代码可以应用过滤等内容:

消费语句将是相同的:

IEnumerable<Product> products = await _productRepository.GetProductList()
    .Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower()))
    .ToListAsync();

...除了这种方式, Where条件将应用于 EF 生成的 SQL,从而实现更高效的查询。 这需要确保 DbContext 实例的范围涵盖调用者和存储库。 (例如,通过依赖注入提供并限定在 web 请求的生命周期内)

如果您不使用单元测试,那么存储库模式不会添加任何内容,直接使用 DbContext 来生成高效查询会更有效。

不确定您要如何解决 null 的情况,但我猜您的情况可以假设它不是以关键字开头的。 Null 条件运算符与 null 结合是您最好的选择。 老实说,您应该始终预期 null 参考并知道您想如何处理它们。 我假设关键字是一个常数,但如果不是,也应该检查 null

products = products
    .Where(x => x?.Name?.ToLower().StartsWith(keyword.ToLower()) ?? false)
    .ToList();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM