对于声明为: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 }