C#Linq技术中SelectMany(...)的内部实现推测
2015-08-31 11:58
429 查看
对于声明为: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。
对于 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。
// 调用的时候是 source.SelectMany(i=>i.listProp,(i,s)=>...); i就是下面的itm // TSource就类似Class;TCollection就类似 Student; TResult则是 第二个委托的返回值的 类型,可以是匿名类型 public IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(source,collectionSelector,resultSelector) { IEnumerable<TResult> listResult = new IEnumerable<TResult>(); // source就类似上面的 classes foreach(var itm in source) { // collectionSelector(itm)返回的是 itm.listProp; // itm.listProp的类型 就是 TCollection 类型。 IEnumerable<TCollection> blockCollection = collectionSelector(itm); // blockCollection类似某class 的studs // 如果没有后面的 resultSelector那么这时候实际上会执行 listResult.AddRange(blockList); // IEnumerable<TResult> blockResult=new List<TResult> foreach(var citm in blockCollection)// 类似上面的studs { // 这里之所以用到 itm 是因为 TResult 中的字段未必都是 citm 里进行了删减,而还包括一些扩增,扩增的 // 字段就可以是 itm中的。 举个栗子: itm是 Trade(有多个Order,即是 blockCollection),而 citm则是 Order, // 那么这时候返回的 Result未必 是 Order的属性缩减后得到的新的 对象,还可以是 itm中除了 blockCollection属性外的 // 其它属性,例如收货人姓名 和 Order中的属性进行拼接。(注意,Order之前是没有收货人姓名的,因为一个 Order必然是 // 属于一个具体的 Trade,而一个Trade是由一个 买家购买物品产生的,故只需要在 Trade中有收件人姓名即可。这里我们 // 将收件人姓名这个属性 整合到了 Order中形成 'Order ,即 TResult。 // 所以说,之前觉得 itm是没必要的是因为自己没有搞懂 这个SelectMany的功能。总以为 对一个结构进行修改形成新的 // 结构只是说 对原来的结构进行 修剪, 现在才知道,实际上还可以 对原来的结构进行 增加,而用什么增加,既可以是 // 无关的数据,也可以是该结构的上级的数据。 listResult.Add(resultSelection(itm, citm)); // resultSelection(itm,citm)的返回值就是 TResult 对象 } } return listResult; }
相关文章推荐
- C#实现主窗体最小化后出现悬浮框及双击悬浮框恢复原窗体的方法
- 使用C#选择文件夹、打开文件夹、选择文件
- C#设置标记方法等为否决的不可用
- c# 九九乘法表
- c#三角形
- c#中的可访问性(小结)
- C#日期函数使用大全
- C# 压缩文件夹及文件
- C#自动添加using引用命名空间
- C#日期函数使用大全
- C#全角和半角转换
- C#循环判断密码
- 问题:C#时间差;结果:C# 使用TimeSpan计算两个时间差
- c#导入导出excel(无格式控制)
- c#基础笔记(1) 枚举
- C# WinForm获取当前路径汇总
- Folder Recursion with C#
- 问题:C# params类型参数;结果:C#的参数类型:params、out和ref
- C#命名规范
- C#泛型