C#中的ThenBy是如何实现的
C#中给继承自IEnumerable的对象(最熟知的就是List了)提供了很丰富的扩展方法,涉及列表操作的方方面面。而扩展方法ThenBy就是很有意思的一个,它的实现也很巧妙。
如果有这样的一个Team类,里面有三个属性。
1 |
|
然后我们有一个Team的List。
1 |
|
那么如何求出teams中得分最高的那个队伍那?这个很简单,只需要一句话即可。
1 |
|
由于List实现了IEnumerable接口,而System.Linq中的Enumerable类中有针对IEnumerable接口的名为OrderByDescending的扩展方法,所以我们直接调用这个扩展方法可以对List按照指定的key进行降序排列,再调用First这个扩展方法来获取列表中的第一个元素。
如果我的List变成这个样子。
1 |
|
由于有可能两组以上的队伍都可能拿到最高分,那么在这些最高分的队伍中,我们选取用时最少的作为最终优胜者。有人说那可以这样写。
1 |
|
先对列表按Score降序排列,再对列表按TimeCost升序排列,然后取结果中的第一个元素。看来貌似是正确的,但其实是错误的。因为第一次调用OrderByDescending方法后返回了一个排序后的数组,再调用OrderBy是另外一次排序了,它会丢弃上一次排序,这与我们定的先看积分,如果积分相同再看耗时的规则违背。
那么应该如何实现那?C#给我们提供了一个叫做ThenBy的方法,可以满足我们的要求。
1 |
|
新的问题又来了。第一次调用OrderByDescending方法时返回的是一个新对象,再对这个新对象调用ThenBy时,它只有记录了上一次排序规则,才能达到我们想要的效果。那么C#是如何记录上次排序使用的key那?
这就先要看OrderByDescending方法是如何实现了的。查看源码发现OrderByDescending有两个重载,实现如下。
1 |
|
在第二个重载中我们看到OrderByDescending方法返回时的是一个继承了IOrderedEnumerable接口的对象OrderedSequence。这个对象记录了我们的排序规则。
而我们再查看下ThenBy方法的定义。
1 |
|
我们可以看到ThenBy这个扩展方法追加到的对象类型要实现IOrderedEnumerable接口,而OrderBy方法恰好返回的就是这个类型接口对象。那我们再看看IOrderedEnumerable接口的定义。
1 |
|
其继承自IEnumerable接口,并且要实现一个名为CreateOrderedEnumerable的方法,正是ThenBy方法实现中调用的这个方法。
所以玄机在OrderedSequence这个类上。实现了IEnumerable接口对象调用OrderBy后会返回OrderedSequence这个对象。而该对象记录了当前排序的规则,其实现了IOrderedEnumerable接口。而ThenBy扩展方法被加到了IOrderedEnumerable接口对象上,其返回值也是一个具有IOrderedEnumerable接口的对象。
照这么说,调用了一次OrderBy后,然后调用多次ThenBy也是可以工作的。我也从官方MSDN中找到了答案:
ThenBy and ThenByDescending are defined to extend the type IOrderedEnumerable, which is also the return type of these methods. This design enables you to specify multiple sort criteria by applying any number of ThenBy or ThenByDescending methods.
翻译为: ThenBy及ThenByDescending是IOrderedEnumerable类型的扩展方法。ThenBy和ThenByDescending方法的返回值也是IOrderedEnumerable类型。这样设计是为了能够调用任意数量的ThenBy和ThenByDescending方法实现多重排序。
至此,ThenBy的神秘面纱就解开了,但是我不知道如何查看OrderedSequence类的源码,如果能看到这个类的源码就太完美了。知道的同学请告知方法。
注: 上述类的源码来自于Mono的实现。
C#中的ThenBy是如何实现的的更多相关文章
- 【转载】C#中使用OrderBy和ThenBy等方法对List集合进行排序
在C#的List操作中,针对List对象集合的排序我们可以使用OrderBy.OrderByDescending.ThenBy.ThenByDescending等方法按照特定的对象属性进行排序,其中O ...
- 年终巨献 史上最全 ——LINQ to SQL语句
LINQ to SQL语句(1)之Where 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句.Where操 ...
- LINQ to SQL语句(5)之Order By
适用场景:对查询出的语句进行排序,比如按时间排序等等. 说明:按指定表达式对集合排序:延迟,:按指定表达式对集合排序:延迟,默认是升序,加上descending表示降序,对应的扩展方法是OrderBy ...
- LINQ TO SQL 大全
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 LINQ to SQL语句(1)之Where 适用场景: ...
- LINQ to SQL大全
LINQ to SQL语句 (1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的 ...
- [转]LINQ To SQL 语法及实例大全
转载自:http://blog.csdn.net/pan_junbiao/article/details/7015633 LINQ to SQL语句(1)之Where Where操作 适用场景:实现过 ...
- LINQ to SQL语句非常详细(原文来自于网络)
LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...
- LINQ To SQL 语法及实例大全
http://blog.csdn.net/pan_junbiao/article/details/7015633 http://blog.csdn.net/pan_junbiao/article/de ...
- 转载linq to sql 的详解
[转]LINQ To SQL 语法及实例大全 2011-11-26阅读38651 评论9 LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL ...
随机推荐
- Asp.net using Oracle.DataAccess.dll access oracle 11g 64bit & x86
使用.net访问oracle数据库时一般需要在机器上安装instantclient才能正常连接. 下面介绍一种不用安装instantclient直接引用dll就用.net能连接oracle数据库的方法 ...
- python面向对象个人总结
基础概念:面向对象其实就是类与对象的使用. 类是模板,对象是实例.模板创建实例,实例去类里面去执行类的方法.类的例子: class Foo: def Bar(self): ...
- Linux内核分析第三周学习总结:构造一个简单的Linux系统MenuOS
韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.Linux内 ...
- Erlang 从入门到精通(一) 下载安装
我的电脑配置: 系统:win8.1 x64 内存:16G 在官网下载http://www.erlang.org/
- C语言课设心得分享(一)
今儿上完课设,老师果然讲的比较少,周四还不用去,看来还是学生自己折腾.我在做课设的过程中,攒了一些心得/体会,希望能和大家分享分享,也希望能一起探讨探讨.如果是我能回答的问题,我很乐意能够提供帮助. ...
- MCS-51系列特殊功能寄存器(摘抄)
1. P0 (80H) P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0 2.SP 栈指针(81H) 3.DPTR 数据指针(由DPH和DPL组成) DPL 数据指针低八 ...
- spilt()的用法
split() 方法用于把一个字符串分割成字符串数组.<script type="text/javascript"> var str="How are you ...
- python-flask 框架使用 flask_mongoengine
开发环境配置 再使用 mongodb 之前,需要先安装 pymongo ,以及flask_mongoengine 1. 切换到 virtualenv 环境 . /pyenv/bin/activate ...
- IOS 从一个小地方想到……
//(一个比较好的地方是 : cancel代表取消的意思,suspended,表示已经挂起,这些英文记住了用来命名挺好的,看看别人的过去时都是加ed的,就是这么强,所以语法不好的话,多关注ios的命名 ...
- android里R.layout.的问题
今天,在Exlipse里的一个项目在.java文件里写 setContentView(R.layout.activity_problem);时,显示错误,以为是R.java文件里没有对应的activ ...