C# LINQ SelectMany with Default
本文关键字:Default with SelectMany LINQ | 更新日期: 2023-09-27 18:05:42
我正在寻找一个优雅的解决方案,将集合中的子集合聚合为一个大集合。我的问题是,当某些子集合可能为空。
,
var aggregatedChildCollection = parentCollection.SelectMany(x=> x.ChildCollection);
如果任何子集合对象为空,则抛出异常。
// option 1
var aggregatedChildCollection = parentCollection
.Where(x=>x.ChildCollection != null)
.SelectMany(x => x.ChildCollection);
// option 2
var aggregatedChildCollection = parentCollection
.SelectMany(x => x.ChildCollection ?? new TypeOfChildCollection[0]);
两者都可以,但是我在父集合上对相当多的子集合做了特定的操作,这变得有点不容易了。
我想要创建一个扩展方法来检查集合是否为空,如果是,则执行选项2所做的—添加一个空数组。但是我对Func的理解还没有到我知道如何编写这个扩展方法的地步。我只知道我想要的语法是这样的:
var aggregatedChildCollection = parentCollection.SelectManyIgnoringNull(x => x.ChildCollection);
是否有一个简单的扩展方法来完成这一点?
您可以使用自定义扩展方法:
public static IEnumerable<TResult> SelectManyIgnoringNull<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
{
return source.Select(selector)
.Where(e => e != null)
.SelectMany(e => e);
}
并像这样使用:
var aggregatedChildCollection = parentCollection
.SelectManyIgnoringNull(x => x.ChildCollection);
如果ParentCollection
是您自己的类,您还应该能够为该类设置默认构造函数,例如:
public ParentCollection{
public ParentCollection() {
ChildCollection = new List<ChildCollection>();
}
}
这应该防止null ref异常,并给你一个空列表,如果它没有任何东西在它。
你的"选项2"是我要做的,有一个小的调整:使用Enumerable.Empty()
而不是创建一个空数组来减少你创建的新对象的数量。
我使用一个简单的扩展方法Touch()
——以*nix实用程序命名——来保持LINQ语法流并减少类型:
public static IEnumerable<T> Touch<T>(this IEnumerable<T> items) =>
items ?? Enumerable.Empty<T>();
并将其用作:
var aggregatedChildCollection = parentCollection
.SelectMany(x => x.ChildCollection.Touch());
您可以通过使用SelectMany
参考源
public static IEnumerable<TResult> SelectManyNotNull<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
foreach (TSource element in source)
{
var subElements = selector(element);
if (subElements != null)
foreach (TResult subElement in subElements )
yield return subElement;
}
}