C#LINQ选择多个默认值
我正在寻找一个优雅的解决方案,将集合中的子集合聚合为一个大集合。我的问题是某些子集合何时可以为null 例如:C#LINQ选择多个默认值,c#,linq,extension-methods,func,C#,Linq,Extension Methods,Func,我正在寻找一个优雅的解决方案,将集合中的子集合聚合为一个大集合。我的问题是某些子集合何时可以为null 例如: var aggregatedChildCollection=parentCollection.SelectMany(x=>x.ChildCollection); 如果任何子集合对象为null,则会引发异常。有些备选方案是: //选项1 var aggregatedChildCollection=parentCollection .Where(x=>x.ChildCollection!
var aggregatedChildCollection=parentCollection.SelectMany(x=>x.ChildCollection);
如果任何子集合对象为null,则会引发异常。有些备选方案是:
//选项1
var aggregatedChildCollection=parentCollection
.Where(x=>x.ChildCollection!=null)
.SelectMany(x=>x.ChildCollection);
//选择2
var aggregatedChildCollection=parentCollection
.SelectMany(x=>x.ChildCollection??新类型的ChildCollection[0]);
这两种方法都能奏效,但我正在对父对象上的许多子集合进行某种操作,而且有点不合适
我想创建一个扩展方法,检查集合是否为null,如果为null,则执行选项2所做的操作—添加一个空数组。但我对Func的理解还不足以让我知道如何编写这个扩展方法。我知道我想要的语法是这样的:
var aggregatedChildCollection = parentCollection
.SelectManyIgnoringNull(x => x.ChildCollection);
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);
}
如果
ParentCollection
是您自己的类,您还应该能够为该类创建默认构造函数,例如:
public ParentCollection{
public ParentCollection() {
ChildCollection = new List<ChildCollection>();
}
}
公共父集合{
公共收藏(){
ChildCollection=新列表();
}
}
这将防止出现null ref异常,如果其中没有任何内容,则会给出一个空列表。至少这对EF模型是有效的。您的“选项2”就是我要做的,只是做了一个小小的调整:使用Enumerable.Empty()
而不是创建一个空数组来减少您正在创建的新对象的数量
我使用一个简单的扩展方法(以*nix实用程序命名)来保持LINQ语法流并减少键入:
public static IEnumerable<T> Touch<T>(this IEnumerable<T> items) =>
items ?? Enumerable.Empty<T>();
通过使用
SelectMany
公共静态IEnumerable SelectManyNotNull(
此IEnumerable源(函数选择器)
{
foreach(源中的TSource元素)
{
var子元素=选择器(元素);
if(子元素!=null)
foreach(子元素中的TResult子元素)
收益子元素;
}
}
否,很遗憾,我不能保证会填充任何子集合。如果子集合为null,则类不是无效的,我只是想将所有子集合分组到一个集合中,并通过将它们视为空集合来忽略任何null。这是一个很好的解决方案—在我的例子中,我将它与Cory Nelson使用Enumerable.empty()的答案相结合
不要删除空集合,这样我至少会有一个空集合。这也行得通,但请注意,Cory链接的代码附带了许可证,因此您需要提供属性。感谢这一点-这是一个很好的资源,很有兴趣了解他们是如何做到的。
var aggregatedChildCollection = parentCollection
.SelectMany(x => x.ChildCollection.Touch());
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;
}
}