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

1
2
    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
public static IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);

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

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

强类型的缺点

比如 web 应用中有如下 Url:

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

1
2
3
4
IQueryable<Order> query = /**/;
string propertyName = /*从请求中获取,OrderDate*/;
bool desc = /*从请求中获取,true*/;
var data = query.Where(/*TODO: 如何写*/).ToArray();

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

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

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

动态构建 keySelector 参数

此部分要求对表达式树有一定了解,可查看:http://msdn.microsoft.com/zh-cn/library/bb397951(v=VS.100).aspx

代码则相当简单:

1
2
3
4
5
6
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 是 LambdaExpression类型的,而 OrderBy 要求是 Expression<Func<Order, DateTime>> 。

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

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

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

1
repository.OrderBy((Expression<Func<Order, DateTime>>)keySelector);

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

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

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

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

或将 keySelector 声明为 dynamic

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

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

OrderBy 扩展方法

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

1
2
3
4
5
6
7
8
9
10
11
public static class QueryableExtensions {
public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string propertyName) {
return OrderBy(queryable, propertyName, false);
}
public static IQueryable<T> OrderBy<T>(this IQueryable<T> 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);
}
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static class QueryableExtensions {
public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string propertyName) {
return QueryableHelper<T>.OrderBy(queryable, propertyName, false);
}
public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string propertyName, bool desc) {
return QueryableHelper<T>.OrderBy(queryable, propertyName, desc);
}
static class QueryableHelper<T> {
private static Dictionary<string, LambdaExpression> cache = new Dictionary<string, LambdaExpression>();
public static IQueryable<T> OrderBy(IQueryable<T> 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;
}
}
}

这里并发不是多大问题,如若考虑,可使用 ConcurrentDictionary<TKey, TValue> 类

使用

很方便的:

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

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

c# 扩展方法 奇思妙用 高级篇 九:OrderBy(string propertyName, bool desc)的更多相关文章

  1. C# 扩展方法奇思妙用高级篇六:WinForm 控件选择器

    在Web开发中,jQuery提供了功能异常强大的$选择器来帮助我们获取页面上的对象.但在WinForm中,.Net似乎没有这样一个使用起来比较方便的选择器.好在我们有扩展方法,可以很方便的打造一个. ...

  2. c# 扩展方法奇思妙用基础篇九:Expression 扩展

    http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html .net 中创建 Expressi ...

  3. c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)

    转载地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html 刚看了篇文章 <Linq的Distin ...

  4. c# 扩展方法奇思妙用基础篇八:Distinct 扩展

    刚看了篇文章 <Linq的Distinct太不给力了>,文中给出了一个解决办法,略显复杂. 试想如果能写成下面的样子,是不是更简单优雅 var p1 = products.Distinct ...

  5. c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展

    Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多 ...

  6. c# 扩展方法奇思妙用

    # 扩展方法出来已久,介绍扩展方法的文章也很多,但都是笼统的.本人最近一直在思考扩展方法的应用,也悟出了一些,准备将这最近一段时间对扩展方法的思考,写成一个系列文章.每个文章只介绍一个应用方面,篇幅不 ...

  7. c# 扩展方法奇思妙用集锦

    本文转载:http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html 其中本人觉得很经典的:c# 扩展方法奇思妙用基础篇五:Dictio ...

  8. EF OrderBy(string propertyname), OrderByDescending(string propertyname) 按属性排序,扩展方法

    public static class LinqExtensions { private static PropertyInfo GetPropertyInfo(Type objType, strin ...

  9. C# 扩展方法集

    语法注意点 可以使用扩展方法来扩展类或接口. 不能重写扩展方法. 扩展方法只能在非嵌套.非泛型静态类内部定义. 扩展方法必须定义在静态类中. 扩展方法的第一个参数的类型用于指定被扩展的类型,它限制该扩 ...

随机推荐

  1. 解析theme()

    drupal_render()只是对theme()的调用做了包装,真正做任务的还是theme(). function theme($hook, $variables = array()) { ... ...

  2. python --curl重定向到文件范例

      import sys import os import subprocess import time start = time.time() old=sys.stdout f=open('test ...

  3. WinForm下的键盘事件(KeyPress、KeyDown)及如何处理不响应键盘事件

    KeyDown事件用来处理功能键:F1 F2 F3... keyPress事件用来处理字符比如说:A B C... 1 2 3... 注:处理该事件时,需要先将窗体的 KeyPreview=true; ...

  4. fatfs文件系统f_lseek追加文件

    http://home.eeworld.com.cn/my/space-uid-430378-blogid-74720.html 这个时候我以为读出的数据应该是stm32f107学习!!!文件系统学习 ...

  5. C# 获取文件MD5、SHA1

    /// <summary> /// 计算文件的 MD5 值 /// </summary> /// <param name="fileName"> ...

  6. C#中将图片转化成base64字符串

    厂址:http://www.cnblogs.com/yunfeifei/p/4165351.html 1.在C#中将图片转化成base64字符串: using System; using System ...

  7. Spring Cloud(一):概述以及核心成员介绍

    什么是Spring Cloud? Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全 ...

  8. Atitit. 悬浮窗口的实现 java swing c# .net c++ js html 的实现

    Atitit. 悬浮窗口的实现 java swing c# .net c++ js html 的实现 1. 建立悬浮窗口引用代码 1 1.1. 定义悬浮窗口,设置this主窗口引用,是为了在悬浮窗口中 ...

  9. [svc]salt基本原理

    转载自:来自:http://tech.mainwise.cn/?p=438 说明:salt是一个异构平台基础设置管理工具(虽然我们通常只用在Linux上),使用轻量级的通讯器ZMQ,用Python写成 ...

  10. JMeter学习笔记(四)

    1. 断言 断言组件是通过获取服务器响应数据,然后根据断言规则去匹配这些响应数据:匹配到是正常现象,此时我们看不到任何提醒,如果匹配不到,即出现了异常情况,此时JMeter就会断定这个事务失败,那么我 ...