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 ...
随机推荐
- Ubuntu 利用 xinetd 限制 SSH 连接数
安装 xinted sudo apt-get install xinetd 修改配置文件 sudo vim /etc/xinetd.conf 在配置文件中加入下列配置 defaults { insta ...
- JavaScript系列:Date对象
<script type="text/javascript"> var oDate = new Date(); var iYear = oDate.getF ...
- 根据excel表格中的内容更新Sql数据库
关于[无法创建链接服务器 "(null)" 的 OLE DB 访问接口 SQL Server 2008读取EXCEL数据时,可能会报这个错误:无法创建链接服务器 "(nu ...
- [转载] Android中Xposed框架篇---利用Xposed框架实现拦截系统方法
本文转载自: http://www.wjdiankong.cn/android%E4%B8%ADxposed%E6%A1%86%E6%9E%B6%E7%AF%87-%E5%88%A9%E7%94%A8 ...
- struts标签,<s:textfield>嵌套<s:property>的问题
错误:org.apache.jasper.JasperException: /front/orderList.jsp(110,122) equal symbol expected <s:te ...
- 使用signal、setjmp、longjmp进行Linux/Android C异常处理
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h&g ...
- Hibernate学习笔记
一.Hibernate基础 1.Hibernate简介 Hibernate是一种对象关系映射(ORM)框架,是实现持久化存储的一种解决方案.Java包括Java类到数据库表的映射和数据查询及获取的方法 ...
- SegmentFault创始人高阳:辍学后带着500元北漂,4年建成国内最大开发者
i黑马注:i黑马曾经和高阳聊过几次天,在他身上我看到了90后CEO特别明显的成功特质“敢为天下先”.在别人犹豫的时候敢第一个出手,在互联网时代往往会取得最关键的“先机优势”. 7月19日,“腾讯产品家 ...
- static关键字用法
java中static关键字可用于修饰: 1.属性:表示该属性变量在类被加载时即被创建并初始化,类加载过程只进行一次,因此静态变量也只被创建一次 2.方法:静态方法为类的公有方法,可直接用‘类名.方法 ...
- Winform中DockPanel(引用WeifenLuo.WinFormsUI.Docking.dll组件)的使用
WeiFenLuo.WinFormsUI.Docking.dll是开源项目DockPanel Suite的一个类库,可实现像Visual Studio的窗口停靠.拖拽等功能.WeifenLuo.Win ...