代码改变世界

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

2011-09-15 17:18 by 鹤冲天, ... 阅读, ... 评论, 收藏, 编辑

.net 中创建 Expression Trees 最简单的方式是使用 lambda 表达式:

1
2
Expression<Func<Person, bool>> exp =
    p => p.Name.Contains("ldp") && p.Birthday.Value.Year > 1990;

其中 Person 类定义如下:

1
2
3
4
public class Person {
    public string Name { get; set; }
    public DateTime? Birthday { get; set; }
}

 

但有些时候,要动态创建 Expression Trees,我们要用到 System.Linq.Expressions 命名空间中的 Expression 类

使用 Expression 类 中的静态方法,前面的 Expression Trees 可如下创建:

1
2
3
4
5
6
7
8
9
10
var parameter = Expression.Parameter(typeof(Person), "p");
var left = Expression.Call(
    Expression.Property(parameter, "Name"),
    typeof(string).GetMethod("Contains"),
    Expression.Constant("ldp"));
var right = Expression.GreaterThan(
    Expression.Property(Expression.Property(Expression.Property(parameter, "Birthday"), "Value"), "Year"),
    Expression.Constant(1990));
var body = Expression.AndAlso(left, right);
var lambda = Expression.Lambda<Func<Person, bool>>(body, parameter);

你应该注意到第 7 行高亮部分,三个重复的 Expression.Property,显得非常臃肿,导致可读性也很差。

可以用下面几个扩展方法予以简化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static class ExpressionExtensions {
    public static Expression AndAlso(this Expression left, Expression right) {
        return Expression.AndAlso(left, right);
    }
    public static Expression Call(this Expression instance, string methodName, params Expression[] arguments) {
        return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);
    }
    public static Expression Property(this Expression expression, string propertyName) {
        return Expression.Property(expression, propertyName);
    }
    public static Expression GreaterThan(this Expression left, Expression right) {
        return Expression.GreaterThan(left, right);
    }
    public static Expression<TDelegate> ToLambda<TDelegate>(this Expression body, params  ParameterExpression[] parameters) {
        return Expression.Lambda<TDelegate>(body, parameters);
    }
}

这五个扩展方法相当简单,没什么技术含量。可以根据自己需要,添加更多的扩展方法。

前面的代码简化成:

1
2
3
4
var parameter = Expression.Parameter(typeof(Person), "p");
var left = parameter.Property("Name").Call("Contains", Expression.Constant("ldp"));
var right = parameter.Property("Birthday").Property("Value").Property("Year").GreaterThan(Expression.Constant(1990));
var lambda = left.AndAlso(right).ToLambda<Func<Person, bool>>(parameter);

是不是好多了。

简单编码,快乐生活!

c#扩展方法奇思妙用》系统文章从 2009 年 08 月开始写起,到现在一共有了 24 篇,欢迎阅读:
基础篇: 中文处理string 常用扩展byte 常用扩展Random 扩展Dictionary<TKey, TValue> 扩展WhereIf 扩展IsBetween 通用扩展WhereIf 扩展Distinct 扩展
高级篇: 改进 Scottgu 的 "In" 扩展Aggregate扩展其改进Enumerable.Cast<T>应用对扩展进行分组管理ToString(string format) 扩展WinForm 控件选择器树”通用遍历器Type类扩展
变态篇: 由Fibonacci数列引出“委托扩展”及“递推递归委托”封装 if/else、swith/case及whileswitch/case 组扩展string 的翻身革命
性能篇 扩展方法性能初测
MVC篇: 巧用扩展方法优先级,美化所有页面TextBoxFor文本框