C#Linq技术中SelectMany(...)的内部实现推测
对于声明为:public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);而言,调用它的形式就是: AList.SelectMany(itm=>itm.listProp); // 其中AList中的属性里有 也是集合的 属性listProp。listProp集合元素类型是TResult。
对于 AList.Select(itm=>itm.listProp)返回的是 IEnumerable<List<TResult>>
现在对于声明为:public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
// TResult 中的字段 可以由 TSource和TCollection一起构成,当然也可以只 由TCollection的某些字段单独构成。
// 可以 假设:Class中有GradeId和ClassId字段和 List<Student> studs,而Student只有ClassId没有GradeId;那么
// IEnumerable<TSource>就是 Class的集合。 而 IEnumerable<TCollection>就是 Class中 Student的集合。
// 这时候调用 SelectMany的形式就是 classes.SelectMany(class=>class.studs,(class,stud)=>new{GradeId=class.GradeId,StudentId=stud.StudentId,...});
// 其中 classes就是 source, stud则是 studs中的元素。且如果方法中出现了两个委托参数,一般而言第二个委托需要间接用到第一个委托的返回值。
// 这个例子就说明了,为什么第二个委托里需要传 class。
1 // 调用的时候是 source.SelectMany(i=>i.listProp,(i,s)=>...); i就是下面的itm
// TSource就类似Class;TCollection就类似 Student; TResult则是 第二个委托的返回值的 类型,可以是匿名类型
2
public IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(source,collectionSelector,resultSelector)
3
{
4
IEnumerable<TResult> listResult = new IEnumerable<TResult>();
// source就类似上面的 classes
5
foreach(var itm in source)
6
{
7
// collectionSelector(itm)返回的是 itm.listProp;
8
// itm.listProp的类型 就是 TCollection 类型。
9
IEnumerable<TCollection> blockCollection = collectionSelector(itm); // blockCollection类似某class 的studs
10
// 如果没有后面的 resultSelector那么这时候实际上会执行 listResult.AddRange(blockList);
11
12
// IEnumerable<TResult> blockResult=new List<TResult>
13
foreach(var citm in blockCollection)// 类似上面的studs
14
{
15
// 这里之所以用到 itm 是因为 TResult 中的字段未必都是 citm 里进行了删减,而还包括一些扩增,扩增的
16
// 字段就可以是 itm中的。 举个栗子: itm是 Trade(有多个Order,即是 blockCollection),而 citm则是 Order,
17
// 那么这时候返回的 Result未必 是 Order的属性缩减后得到的新的 对象,还可以是 itm中除了 blockCollection属性外的
18
// 其它属性,例如收货人姓名 和 Order中的属性进行拼接。(注意,Order之前是没有收货人姓名的,因为一个 Order必然是
19
// 属于一个具体的 Trade,而一个Trade是由一个 买家购买物品产生的,故只需要在 Trade中有收件人姓名即可。这里我们
20
// 将收件人姓名这个属性 整合到了 Order中形成 ‘Order ,,即 TResult。
21
// 所以说,之前觉得 itm是没必要的是因为自己没有搞懂 这个SelectMany的功能。总以为 对一个结构进行修改形成新的
22
// 结构只是说 对原来的结构进行 修剪, 现在才知道,实际上还可以 对原来的结构进行 增加,而用什么增加,既可以是
23
// 无关的数据,也可以是该结构的上级的数据。
24
listResult.Add(resultSelection(itm, citm)); // resultSelection(itm,citm)的返回值就是 TResult 对象
25
}
26
}
27
return listResult;
28
}
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/67863.html