轻轻松松学习Linq排序
创始人
2024-06-07 02:51:17
0

Linq排序在一系列Linq操作中应该使用频率***的,关于Linq排序的文章也很多,但是笔者的这篇文章最值得一读了,因为他把理论与实践结合的十分***,理解起来也很简单,希望能给你带来帮助。

在程序开发中,对数据进行排序是很常见的操作。现在就来演示一下Linq排序,假设现在有一个类Customer,定义如下所示:

  1. public class Customer  
  2. {  
  3. public string Id { get; set; }  
  4. public string Name { get; set; }  
  5. public decimal Age { get; set; }  

我们现在要对很多Customer对象进行排序,最简单的就是使用Linq排序的orderby子句:

  1. from c in Customers orderby c.Id select c; 

上面实现了按照Id来进行Linq排序。可是需求变了,用户现在想用Name来排序。好办!把上面的改一改比如下面这样就可以了:

  1. from c in Customers orderby c.Name select c; 

可是需求又变了,用户现在说,你在程序中不能写死,得列一个菜单,我点哪个你就按哪个给我Linq排序。这个也不难办:

  1. var searchResult = from c in Customers select c;  
  2. if (columnName == "Id")  
  3. {  
  4. searchResult = from c in Customers orderby c.Id select c;  
  5. }  
  6. else if (columnName == "Name")  
  7. {  
  8. searchResult = from c in Customers orderby c.Id select c;  
  9. }  
  10. else ...  

这确实解决了问题,可是这样的代码不易维护。如果加属性了怎么办?如果属性改名字了怎么办?如果有好多的不同的类都需要这样的Linq排序怎么办?

下面我介绍一种较为通用的解决方案,此方案的核心技术是反射(Reflection)和扩展方法(Extension Methods)。

  1. public static IOrderedQueryable OrderBy(  
  2. this IQueryable source,  
  3. Expression> keySelector,  
  4. IComparer comparer  

参数source是一个用来排序的对象,keySelector是用来取出用来Linq排序的键的函数,comparer(比较器)用来比较取出的两个键值。

对象的属性类型可能多种多样,而我们又不想为每种类型分别指定comparer(因为那样做的话也将是一堆if else…)。变通一下思路,不管遇到哪种类型的属性,我们都先把它的值放到一个共同的容器中,然后为这个容器写一个comparer类。我们把类型判断留到了这个comparer中,因为类型是有限的,至少我们需要处理的那些属性的类型是有限的。
上面提到的这个值的容器也是一个类,定义如下:

  1. public class CommonComparableValue  
  2. {  
  3. public object RealValue { get; set; }  

相应的比较类定义如下:

  1. public class CommonComparableValueComparer : IComparer  
  2. {  
  3. public int Compare(CommonComparableValue x, CommonComparableValue y)  
  4. {  
  5. string s = x.RealValue as string;  
  6. if (s != null)  
  7. {  
  8. return s.CompareTo(y.RealValue);  
  9. }  
  10. int? i = x.RealValue as int?;  
  11. if (i != null)  
  12. {  
  13. return i.Value - (int)y.RealValue;  
  14. }  
  15. decimal? d = x.RealValue as decimal?;  
  16. if (d != null)  
  17. {  
  18. return d.Value.CompareTo((decimal)y.RealValue);  
  19. }  
  20. throw new NotImplementedException("NotImplemented Data Type!!!");  
  21. }  

这里的比较类只用到了int,string等几种类型,如果属性有其它的类型,也应该在这里添加。从代码实现可以看出,即使属性的类型是复杂数据类型也可以这么处理。

现在来看keySelector的实现。它是用来取出待比较的属性值的函数。这个函数应该是这个样子的:

  1. public delegate TResult Func  
  2. ( T  arg ) 

在这里,T的类型就是Customer,TResult就是刚刚已经那个存放任意属性类型的值的容器CommonComparableValue。

在这个实现取键值的函数里,我们只有一个Customer类型的参数arg可用,而那个用来Linq排序的属性名字是在运行期间确定的,如何才能取出我们想要的属性的值呢?方法是这样的,先通过扩展方法为Customer加一个名为GetSortingKeyValue的取键值方法,代码如下:

  1. public static class CustomerSortExtension  
  2. {  
  3. public static CommonComparableValue GetSortingKeyValue(this Customer ainfo, string columnName)  
  4. {  
  5. Type t = ainfo.GetType();  
  6. PropertyInfo pinfo = t.GetProperty(columnName);  
  7. if (pinfo == null)  
  8. {  
  9. throw new Exception("Property " + columnName + "not found");  
  10. }  
  11. else 
  12. {  
  13. return new CommonComparableValue  
  14. {  
  15. RealValue = pinfo.GetValue(ainfo, null)  
  16. };  
  17. }  
  18. }  

这里就是通过一个字符串获取属性值,核心是反射。接下来只要在那个keySelector方法中调用GetSortingKeyValue方法就可以了。

到这里,各种准备活动就做完了。现在来看一下怎么把这些东西组织起来实现Linq排序:

  1. var searchResult = from c in Customers select c;  
  2. Func myFunc = x => x.GetSortingKeyValue(columnName);  
  3. CommonComparableValueComparer comparer = new CommonComparableValueComparer();  
  4. searchResult = searchResult.OrderBy(myFunc, comparer); 

这种方案的主要内容到这里就介绍完了。

***提一下,如果你想把这些东西用到你的代码中,你一般需要做的只有:将扩展方法的***个参数改为你需要Linq排序的那个类型。比如要为Person排序,扩展方法则可以是这个样子:

  1. public static CommonComparableValue GetSortingKeyValue(this Customer ainfo, string columnName) 

当然,那个CommonComparableValueComparer类也应该根据实际类型修改以支持更多的属性类型。

以上就是对Linq排序的详细介绍,从理论到方法,很有价值的一篇文章呦!

【编辑推荐】

  1. 为你揭晓 Linq更新数据是否真的实用?
  2. 深度剖析linq级联删除
  3. 简单实现Linq连接查询
  4. LINQ动态查询的实现浅析
  5. 简单实现Linq多条件查询

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...