下面是 中最常用的两个排序的扩展方法:
12 | public static IOrderedQueryable |
算上另外两个复杂点的,一共是四个方法,都是强类型的。
虽然强类型优点多多,但有些情况下确显得不够灵活。
强类型的缺点
比如 web 应用中有如下 Url:
在代码中我们如何写出强类型的查询?
1234 | IQueryable |
单凭 中定义的 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 |
但这样一来,又成了硬编码。
我们期望灵活,解决方法有很多种,这里只介绍最简单的一种,借助 .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 |
注意,上面代码执行没问题,但效率不好。因为每次都要动态生成表达式树,另外动态调用也会造成一定性能损失。
想提高效率的话,可把动态生成的表达式树缓存起来,参考如下:
1234567891011121314151617181920212223 | public static class QueryableExtensions { public static IQueryable |
这里并发不是多大问题,如若考虑,可使用 。
使用
很方便的:
12 | var data1 = productRepository.OrderBy("Name");var data2 = orderRepository.OrderBy("OrderDate", true); |
http://www.cnblogs.com/ldp615/archive/2012/01/15/orderby-extensions.html