动态构建Expression表达式树

简介: 话说.Net已经发展到4.5了,大家对Lambda和Linq应该比较熟悉了。比如我们要取出产品集合里面SKU以"123"开头的产品集,就可以这么写:Products=Products.Where(p=>p.SKUCode.StartWith("123")); 现下有这么个需求,用户输入以逗号分隔的字符串,求取SKU以分隔的字符串开头的产品集,如用户输入"123,234,456",那么就取出SKU以"123"开头或以"234"开头或以"456"开头的产品集合。

话说.Net已经发展到4.5了,大家对Lambda和Linq应该比较熟悉了。比如我们要取出产品集合里面SKU以"123"开头的产品集,就可以这么写:
Products=Products.Where(p=>p.SKUCode.StartWith("123"));

现下有这么个需求,用户输入以逗号分隔的字符串,求取SKU以分隔的字符串开头的产品集,如用户输入"123,234,456",那么就取出SKU以"123"开头或以"234"开头或以"456"开头的产品集合。于是我计上心头,欲以循环解之,无解。为什么呢?因为这里有个关键字“或”。假如是“并”需求,我们大可信手拈来,如下:

1 string[] starts = input.Split(',');
2 foreach (string start in starts)
3 {
4     Products = Products.Where(p => p.SKUCode.StartWith(start));
5 }

对于“或”来说,Linq似乎并没有提供一个明确的方法(比如这里的Where)供我们使用,我想是因为“或”的作用域比较难用程序语言界定,因此一旦使用“或”去联接,那最终的结果可能并不是预期的。若“或”对应的方法是Or,那么循环体内的语句变为Products = Products.Or(p => p.SKUCode.StartWith(start));不知所云。我们想要的其实应该是条件的拼接:
p => p.SKUCode.StartWith(start1) || p.SKUCode.StartWith(start2) || p.SKUCode.StartWith(start3) || ……

可惜Linq同样没有给我们提供动态拼接条件的方便的语法(何为方便,我的想法是同字符串拼接,拼接完毕后可简单快捷地转成可执行的语句。啥,你说Javascript?心里想想就是了,说出来干嘛),不过给了稍稍复杂点的方式。下面是代码: 

 1 /// <summary>
 2 /// 根据条件数据动态生成或连接条件
 3 /// </summary>
 4 /// <typeparam name="TSource">集合项类型</typeparam>
 5 /// <param name="sourcePropertyName">待比较的集合项属性</param>
 6 /// <param name="methodName">方法名称</param>
 7 /// <param name="objs">条件数据</param>
 8 /// <returns></returns>
 9 public static Expression<Func<TSource, bool>> GenerateOrElseConditionWithArray<TSource>(string sourcePropertyName, string methodName, IEnumerable<object> objs)
10 {
11     if (objs != null && objs.Count() > 0)
12     {
13         var len = objs.Count();
14         var p = Expression.Parameter(typeof(TSource), "p");
15         var propertyName = Expression.Property(p, sourcePropertyName);
16         var body = Expression.Equal(Expression.Call(propertyName, methodName, null, Expression.Constant(objs.First())), Expression.Constant(true));
17         for (int i = 1; i < len; i++)
18         {
19             var pcode = objs.ElementAt(i);
20             body = Expression.OrElse(body, Expression.Call(propertyName, methodName, null, Expression.Constant(pcode)));
21         }
22         Expression<Func<TSource, bool>> orExp = Expression.Lambda<Func<TSource, bool>>(body, p);
23         return orExp;
24     }
25     return null;
26 }

 上述代码是我较早时候写的,此时看似乎有些不妥之处,最近较忙,也懒于润色修改了,欢迎朋友指正。

现在我们就可以这么实现上述需求:

1 string[] starts = input.Split(',');
2 var codeExp = GenerateOrElseConditionWithArray<Product>("SKUCode", "StartsWith", starts);
3 if (codeExp != null)
4     Products = Products.Where(codeExp);

 

后记:老外写了一个类,貌似比我的专业多了,Dynamically Composing Expression Predicates.

 

 转载请注明本文出处:http://www.cnblogs.com/newton/archive/2012/12/17/2821159.html

目录
相关文章
|
5月前
|
SQL 开发框架 前端开发
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
|
4月前
|
存储
访问者模式问题之在 extractFunctions 方法中, FunctionCallExpression 类型的 Expression如何处理
访问者模式问题之在 extractFunctions 方法中, FunctionCallExpression 类型的 Expression如何处理
|
7月前
|
C#
C#动态查询:巧用Expression组合多条件表达式
在C#中,利用`Expression`类和`AndAlso`、`OrElse`方法,可以组合两个`Expression&lt;Func&lt;T, bool&gt;&gt;`以实现动态多条件查询。该方法通过构建表达式树,方便地构建复杂查询。示例代码展示了如何创建表达式树,分别检查年龄大于等于18和姓名为&quot;John&quot;的条件,并使用`AndAlso`组合这两个条件,最终编译为可执行的委托进行测试。
286 1
Thymeleaf ${}中的表达式本质是OGNL-分支与迭代-包含其他模板文件
Thymeleaf ${}中的表达式本质是OGNL-分支与迭代-包含其他模板文件
74 0
|
SQL 开发框架 .NET
C#表达式树 创建、生成、使用、lambd a转成表达式树~表达式树的知识详解
C#表达式树 创建、生成、使用、lambd a转成表达式树~表达式树的知识详解
298 0
C#表达式树 创建、生成、使用、lambd a转成表达式树~表达式树的知识详解
|
SQL 监控
表达式树的解析(一)
表达式树的解析(一)
139 0
表达式树的解析(一)
表达式树的解析(二)
表达式树的解析(二)
158 0
表达式树的解析(二)
|
索引
改善代码设计 —— 简化条件表达式(Simplifying Conditional Expressions)
  系列博客       1. 改善代码设计 —— 优化函数的构成(Composing Methods)       2. 改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects)       3.
941 0
|
索引
改善代码设计 —— 简化“.NET技术”条件表达式(Simplifying Conditional Expressions)
  系列博客       1. 改善代码设计 —— 优化函数的构成(Composing Methods)       2. 改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects)       3.
859 0