博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c# 扩展方法 奇思妙用 高级篇 九:OrderBy(string propertyName, bool desc)
阅读量:4616 次
发布时间:2019-06-09

本文共 4240 字,大约阅读时间需要 14 分钟。

下面是  中最常用的两个排序的扩展方法:

12
public static IOrderedQueryable
OrderBy
(this IQueryable
source, Expression
> keySelector); public static IOrderedQueryable
OrderByDescending
(this IQueryable
source, Expression
> keySelector);

算上另外两个复杂点的,一共是四个方法,都是强类型的。

虽然强类型优点多多,但有些情况下确显得不够灵活。

强类型的缺点

比如 web 应用中有如下 Url:

在代码中我们如何写出强类型的查询?

1234
IQueryable
query = /**/;string propertyName = /*从请求中获取,OrderDate*/;bool desc = /*从请求中获取,true*/;var data = query.Where(/*TODO: 如何写*/).ToArray();

单凭  中定义的 OrderBy 和 OrderByDescending, 是不可能简单直接写出来的,除非硬编码。

那有如此做到灵活呢?我们从  定义的 OrderBy 和 OrderByDescending 方法下手,它们均有一个 Expression<Func<TSource, TKey>> 类型的 keySelector 参数。

先来试下能不能动态构建一个 keySelector。

动态构建 keySelector 参数

此部分要求对表达式树有一定了解,可查看:

代码则相当简单:

123456
var type = typeof(Order);var propertyName = "OrderDate";//var param = Expression.Parameter(type, type.Name);var body = Expression.Property(param, propertyName);var keySelector = Expression.Lambda(body, param);

 

最后三行代码动态构造了一颗表达式树:

和我们使用 lambda 表达式写出的效果是完全一样的:

这步比较顺利,下面来看如何调用:

调用 OrderBy

直接传入调用是不行的:

1
repository.OrderBy(keySelector);

因为前面构建的 keySelector 是 类型的,而 OrderBy 要求是 Expression<Func<Order, DateTime>> 。

但实质上 keySelector 就是 OrderBy 要求的类型:

因为强类型,居然不认自家人了!

可以通过强制类型转换来解决,编译运行都没问题:

1
repository.OrderBy((Expression
>)keySelector);

但这样一来,又成了硬编码。

我们期望灵活,解决方法有很多种,这里只介绍最简单的一种,借助 .net 4 中 :

1
var orderedQueryable = Queryable.OrderBy(repository, (dynamic)keySelector);

因为扩展方法是不能被动态调用的(Extension methods cannot be dynamically dispatched),所以写成上面样子。

或将 keySelector 声明为 :

12
dynamic keySelector = Expression.Lambda(body, param);var orderedQueryable = Queryable.OrderBy(repository, keySelector);

 

OK,搞定!根据属性名排序太常用了,遂提取成了扩展方法:

 

 

OrderBy 扩展方法

将上面代码整理下,扩展方法就出来了:

1234567891011
public static class QueryableExtensions {    public static IQueryable
OrderBy
(this IQueryable
queryable, string propertyName) { return OrderBy(queryable, propertyName, false); } public static IQueryable
OrderBy
(this IQueryable
queryable, string propertyName, bool desc) { var param = Expression.Parameter(typeof(T)); var body = Expression.Property(param, propertyName); dynamic keySelector = Expression.Lambda(body, param); return desc ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector); }}

注意,上面代码执行没问题,但效率不好。因为每次都要动态生成表达式树,另外动态调用也会造成一定性能损失。

想提高效率的话,可把动态生成的表达式树缓存起来,参考如下:

 

1234567891011121314151617181920212223
public static class QueryableExtensions {    public static IQueryable
OrderBy
(this IQueryable
queryable, string propertyName) { return QueryableHelper
.OrderBy(queryable, propertyName, false); } public static IQueryable
OrderBy
(this IQueryable
queryable, string propertyName, bool desc) { return QueryableHelper
.OrderBy(queryable, propertyName, desc); } static class QueryableHelper
{ private static Dictionary
cache = new Dictionary
(); public static IQueryable
OrderBy(IQueryable
queryable, string propertyName, bool desc) { dynamic keySelector = GetLambdaExpression(propertyName); return desc ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector); } private static LambdaExpression GetLambdaExpression(string propertyName) { if (cache.ContainsKey(propertyName)) return cache[propertyName]; var param = Expression.Parameter(typeof(T)); var body = Expression.Property(param, propertyName); var keySelector = Expression.Lambda(body, param); cache[propertyName] = keySelector; return keySelector; } }}

 

这里并发不是多大问题,如若考虑,可使用 。

使用

很方便的:

12
var data1 = productRepository.OrderBy("Name");var data2 = orderRepository.OrderBy("OrderDate", true);

http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html

 

转载于:https://www.cnblogs.com/sjqq/p/8635458.html

你可能感兴趣的文章
在DataGridView控件中实现冻结列分界线
查看>>
python3之线程(一)
查看>>
扑克牌之发牌
查看>>
mysql 必会基础3
查看>>
linux/mac系统的软链接文件与硬链接文件
查看>>
(一)java并发知识图谱
查看>>
漫步ASP.NET MVC的处理管线
查看>>
MySQL跑得慢的原因分析
查看>>
ThoughtWorks 一道面试题及解法
查看>>
PL/SQL语言的学习笔记
查看>>
c#笔记
查看>>
linux简单实用的命令整理
查看>>
列表和字符串的转换及statswith,endswith的应用判断
查看>>
rename 表名
查看>>
numpy array或matrix的交换两行
查看>>
liunx 端口权限
查看>>
【2015】给一个不多于三位的正整数,求出它是几位数,并分别打印出各位上的数字。...
查看>>
C++中string类的操作函数。
查看>>
65条常用的正则表达式
查看>>
Vscode断点调试PHP
查看>>