我们先来假设这种场景:

一个学校中有多个年级,一个年级有多个班级,一个班级里有多个学生。这里我们只需要班级、年级、和学生这三个概念;

让我们先来定义Class类和Student类:

    // 注意,Class是班级而不是 教室的意思,教室是 Classroom。
public class Class
{
public int ClassId { get; set; }
// 同一个班级的学生必然是属于同一个年级的,故GradeId直接在Class中声明就可以了。
public int GradeId { get; set; }
public List<Student> Students { get; set; }
} public class Student
{
public int StudentId { get; set; }
// 外键 ClassId
public int ClassId { get; set; }
       public string OtherProp{ get; set; }
// 注意,学生没有GradeId属性
}

现在来声明多个班级:

List<Class> classes = new List<Class>();
classes.AddRange(...); // 这里添加的Class是有属于不同年级

现在来看SelectMany(...);函数的声明:

声明一:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
声明二:
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

对于第一个声明:我们调用该函数的形式即为:

classes.SelectMany(cls=>cls.Students);  // 这里很重要的一点,Func<TSource,IEnumerable<TResult>>里面的不是参数,而是类型,Func中最后一个泛型一定是返回值的泛型类型
// 这里classes 就是函数原型声明中的 source,而TSource就是Class类型,TResult就是 Student类型;而对于委托参数 selector中的 IEnumerable<TResult>实际上就是当前cls
// 代表的班级的所有学生,直接用cls.Students即可(而不是说自己声明一个 IEnumerable<Student> studs,然后将studs传到Func中,该Func只有一个参数)。

如上所示的代码实际上就是将多个班级classes中的所有学生都选出来返回一个 IEnumerable<Student> students,但是这里会存在一个问题,就是students中的学生

是classes中的学生总和,但是这时候我们无法知道students中某学生所属的年级是哪个了,如果想在返回classes中所有学生的集合的同时,对Student删减一些属性和

增加GradeId属性,这时候可以用第二个声明的SelectMany(..)函数,调用方法如下:

// 这里 cls就是声明二中的对应第一个委托Func的参数,TSource就是Class类型,cls.Students即是IEnumerable<TCollection>类型返回值,TCollection就是Student类型
// 而stud 就是cls.Students中的某一个元素,new{....}返回的类型是匿名类型,就是 TResult类型。
classes.SelectMany(cls=>cls.Students,(cls,stud)=>new{
ClassId=stud.ClassId,GradeId=cls.GradeId,StudentId=stud.StudentId}); // 这里的属性的增减 形式是随自己需要来改变的,不一定就是要这样

这时候返回的 IEnumerable<TResult> ches变量就是 对原来的Student进行了属性增减后的新类型(匿名类型'a)的集合,ches集合的元素个数和之前

classes.SelectMany(cls=>cls.Students)返回的元素个数是一样的。这时候要遍历ches 就不能用具体类型,只能用XXX(var itm in ches) 了。

现在来看看第二个声明的SelectMany(...)的内部实现的一种方式及其伪代码:

     // TResult对应 'a匿名类型;TSource对应Class类型;TCollection对应Student类型
// source 对应classes
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
IEnumerable<TResult> listResult = new IEnumerable<TResult>();
// source 对应 classes
foreach(var cls in source)
{
// TCollection对应Student,blockStudents对应 当前班级 cls中的所有学生集合
// 给collectionSelector传 Lambda表达式时给出了该委托承载的 函数的具体声明 cls=>cls.Students。
// Lambda表达式产生的 匿名函数的 参数类型,返回值类型一定是已知的,这里是Class和IEnumerable<Student>
IEnumerable<TCollection> blockStudents = collectionSelector(cls); /* 如果是第一个声明,那么这时候就会开始执行 listResult.AddRange(blockStudents);此时Student即是TResult*/ foreach(var stud in blockStudents) // 注意,这是第二层 foreach
{
// resultSelection(cls,stud) 返回的是 TResult,即匿名类型 'a 的实体对象,并添加到 listResult中
// resultSelection承载的Lambda表达式为:(cls,stud)=>new {ClassId.......GradeId...} ;new出的
// 匿名对象即为 TResult 类型。
listResult.Add(resultSelection(cls, stud));
} // Second Foreach End
} // First Foreach End
return listResult;
} // SelectMany(...) End

C#Linq技术中SelectMany(...)函数的内部实现的伪代码的更多相关文章

  1. C#Linq技术中SelectMany(...)的内部实现推测

    对于声明为:public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable&l ...

  2. C++中的多态与虚函数的内部实现

    1.什么是多态         多态性可以简单概括为“一个接口,多种行为”.         也就是说,向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法).也就是说,每个对象可 ...

  3. Android逆向之旅---基于对so中的函数加密技术实现so加固

    一.前言 今天我们继续来介绍so加固方式,在前面一篇文章中我们介绍了对so中指定的段(section)进行加密来实现对so加固 http://blog.csdn.net/jiangwei0910410 ...

  4. 改变JavaScript中函数的内部this指向!

    改变JavaScript中函数的内部this指向! 第一种方法 call call 可以 调用函数 + 改变函数内的this指向! var obj = { name: 'lvhang' } funct ...

  5. [SAP ABAP开发技术总结]日期函数

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  6. 《APUE》中的函数整理

    第1章 unix基础知识 1. char *strerror(int errnum) 该函数将errnum(就是errno值)映射为一个出错信息字符串,返回该字符串指针.声明在string.h文件中. ...

  7. 【PHP】最详细PHP从入门到精通(二)——PHP中的函数

     PHP从入门到精通 之PHP中的函数 各位开发者朋友大家好,自上次更新PHP的相关知识,得到了大家的广泛支持.PHP的火爆程度不言而喻,函数作为PHP中极为重要的部分,应诸位的支持,博主继续跟进更新 ...

  8. 浅谈Kotlin中的函数

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/UV23Uw_969oVhiOdo4ZKAw作者:连凌能 Kotlin,已经被Android官方 ...

  9. 《python解释器源码剖析》第12章--python虚拟机中的函数机制

    12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python ...

随机推荐

  1. jq 时间计算

    -(function($){ var caculation = function(gap){ var minutes = 1000 * 60 var hours = minutes * 60 var ...

  2. Python 简单socket模拟ssh

    OSI七层模型(Open System Interconnection,开放式系统互联) 应用层 表示层 回话层 传输层 tcp,udp 网络层 ip,icmp 数据链路层 mac地址 物理层 物理网 ...

  3. RecyclerView.ItemDecoration

    decoration 英文意思: 英[ˌdekəˈreɪʃn] 美[ˌdɛkəˈreʃən] n. 装饰品; 装饰,装潢; 装饰图案,装饰风格; 奖章; [例句]The decoration and ...

  4. MySQL分类表设计--根据ID删除全部子类

    在做数据库分类表的时候,通常会有这样的设计:一个字段是ID,另一个字段PID,PID指向自己的上级分类: 这样的设计带来的问题是:我要删除一个类,我希望它的子类全部一起删除: 在不知道分类有多少层级的 ...

  5. 杭电ACM——自我强化步骤

    第一阶段:开始入门吧!(15天,53题) http://blog.csdn.net/always2015/article/details/44966019#t0 一.输入输出练习(2天,10题) 10 ...

  6. python利用scrapy框架爬取起点

    先上自己做完之后回顾细节和思路的东西,之后代码一起上. 1.Mongodb 建立一个叫QiDian的库,然后建立了一个叫Novelclass(小说类别表)Novelclass(可以把一级类别二级类别都 ...

  7. 崩溃 golang入坑系列

    早上(11.30)收到邮件,Vultr东京机房网络故障.当时搭建SS时,考虑到了机房故障.所以特意分出了日本和香港两条线路.但千算万算,忘记数据库还在东京机房中. 现在网络故障,SS服务器无法读取数据 ...

  8. 问题记录-运行Tomcat,项目程序没有响应

    问题描述:运行Tomcat,项目程序没有响应原因在于 修改成一致路径即可解决.

  9. 51Nod 1090 3个数和为0 set 二分优化

    给出一个长度为N的无序数组,数组中的元素为整数,有正有负包括0,并互不相等.从中找出所有和 = 0的3个数的组合.如果没有这样的组合,输出No Solution.如果有多个,按照3个数中最小的数从小到 ...

  10. php简单实现发微博动态

    首先,肯定是注册成为开发者新浪微博开放平台 选择网站应用,填写一些基本信息 填完后在'我的应用'中,会看到刚创建的应用信息,我们只是简单的测试一下,所以其他复杂的注册信息都不用填写,有这些就够了 很重 ...