![](/img/trans.png)
[英]Foreach throws NullReferenceException on not null IEnumerable with elements
[英]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.