首页 > 其他分享 >关于Expression表达式树的拼接

关于Expression表达式树的拼接

时间:2022-12-16 17:56:06浏览次数:67  
标签:string param 拼接 typeof Expression 表达式 left

最近在做项目中遇到一个问题,需求是这样的:

我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有.

我们用的MVC+EF5.0的框架,在BLL层进行查询的 时候需要构建lambda表达式来作为查询条件,但是,我们怎么来构建lambda来确定查询的条件呢?我们知道Express<Func<T,bool>>这样的一个参数可以是lambda表达式,但是这里的按条件拼接式不能使用委托链的形式的.当然还有一种解决办法,我把所有查询条件都写好,然后根据传过来的ID 或者用户名 来判断确定使用哪个..这样的判断逻辑混乱,代码冗长,我们就想找一个可以动态拼接查询条件的方法.

即按照id 或者用户名是否存在动态的来拼接查询条件.

首先我们需要知道,表达式构成部分,表达式是有两部分构成,Parameter和body,第一个是参数,第二个是表达式体,表达式体是二进制的位运算,也就是 比如(left&right)而left和right要返回的值必须是基本类型的值,也就是可以参与位运算的值.例如(a,b)=>()这个lambda表达式中,ab是参数,括号后面中是表达式体这里面返回的值只能是基本类型.我们要构建一个表达式树,主要就是构建这个表达式体,那么这个表达式体是一个什么样的类型呢 ?BinaryExpression类型,我们只需要构造这个类型,然后通过Expression.And(left,right)或者Expression.Or()这两个方法来构造即可. 这个两个方法返回值就是BinaryExpression的类型对象.然后我们在用Expression.Lambda<Func<T,bool>>(BinaryExpression,Parameter)这个方法将这个表达式树转化为lambda的表达式.这就是这个问题的 解决思路,来看看我们是怎么来实现的.

首先我们定义了一个表达式变量.

Expression<Func<UserInfo, bool>> where;

然后我们开始进行labmda的构造

接下来,我们来构造参数和必要条件,也是就lambda中的c=>()中的c

 

  1.   ParameterExpression param = Expression.Parameter(typeof(UserInfo), "c");//c=>
  2.    
  3.   //c=>c.IsDelete==false这里需要不被删除的条件
  4.    
  5.   MemberExpression left1 = Expression.Property(param, typeof(UserInfo).GetProperty("IsDelete"));构建c.IsDelete
  6.    
  7.   ConstantExpression right1 = Expression.Constant(false);//构建一个常量 false
  8.    
  9.   BinaryExpression be = Expression.Equal(left1, right1);构建//c=>c.IsDelete==false 就是现在这个be了

 

下面 我们需要根据我们的条件 也就是id和用户名字符串来继续拼接这个表达式

首先我们来拼接c.UserId==sid

 

  1.   if (!string.IsNullOrEmpty(Request["sid"]))
  2.    
  3.   {
  4.    
  5.   //c.UserId==sid
  6.    
  7.   int sid = int.Parse(Request["sid"]);
  8.    
  9.   //根据参数的属性构造左表达式c.UserId
  10.    
  11.   MemberExpression left2 = Expression.Property(param, typeof(UserInfo).GetProperty("UserId"));
  12.    
  13.   //构造右表达式sid
  14.    
  15.   ConstantExpression right2 = Expression.Constant(sid);
  16.    
  17.   //进行合并:cUserId==sid
  18.    
  19.   BinaryExpression where2 = Expression.Equal(left2, right2);
  20.    
  21.   //将这个条件与上一个条件进行与合并:c.IsDelete==false && c.UserId==sid

 

现在我们来拼接第二个条件

前面我们已经说过,表达式体需要返回的是可以做二进制运算的类型,但是这是个值类型字符串,该怎么办呢?

在参考了MSDN中的Expression方法中,发现有这样的一个方法.Expression.Call().

然后看了示例这个

 

究竟是用来干嘛的??

我们可以用这个call’方法 ,来调用一个类型 中的一个方法,然后产生一个MethodCallExpression类型的返回值,这样,我们来调用string. Contains方法不就可以完成我们想要的表达式了么?

且看下面的 代码

 

  1.   //c.UserName.Contains(sname)
  2.    
  3.   if (!string.IsNullOrEmpty(Request["sname"]))
  4.    
  5.   {
  6.    
  7.   string sname = Request["sname"];
  8.    
  9.   MemberExpression left3 = Expression.Property(param, typeof(UserInfo).GetProperty("UserName"));//这里构造c.UserName这个属性表达式.
  10.    
  11.   ConstantExpression right3 = Expression.Constant(sname);//这里构造sname这个常量表达式
  12.    
  13.   MethodCallExpression where3 = Expression.Call(left3, typeof(string).GetMethod("Contains"), right3);这里我们用Call这个方法完成/c.UserName.Contains(sname)这个lambda这个表达式的实现.
  14.    
  15.   be = Expression.And(be, where3);//拼接刚才的be表达式,
  16.    
  17.   }
  18.    
  19.   where = Expression.Lambda<Func<UserInfo, bool>>(be, param);//生成最后需要的带参数的表达式树.

 

这样我们的表达式树拼接就完成了.

至于运行结果就不为大家贴图了,可以运行和lambda的结果一样.可以完成两个条件的查询.

下面,封装了这个表达式树的帮助类.大家可以参考.

 

  1.   public class WhereHelper<T>
  2.    
  3.   where T:class
  4.    
  5.   {
  6.    
  7.   private ParameterExpression param;
  8.    
  9.   private BinaryExpression filter;
  10.    
  11.   public WhereHelper()
  12.    
  13.   {
  14.    
  15.   param = Expression.Parameter(typeof (T), "c");
  16.    
  17.   //1==1
  18.    
  19.   Expression left = Expression.Constant(1);
  20.    
  21.   filter = Expression.Equal(left, left);
  22.    
  23.   }
  24.    
  25.   public Expression<Func<T, bool>> GetExpression()
  26.    
  27.   {
  28.    
  29.   return Expression.Lambda<Func<T, bool>>(filter,param);
  30.    
  31.   }
  32.    
  33.   public void Equal(string propertyName,object value)
  34.    
  35.   {
  36.    
  37.   Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));
  38.    
  39.   Expression right = Expression.Constant(value, value.GetType());
  40.    
  41.   Expression result = Expression.Equal(left, right);
  42.    
  43.   filter = Expression.And(filter, result);
  44.    
  45.   }
  46.    
  47.   public void Contains(string propertyName,string value)
  48.    
  49.   {
  50.    
  51.   Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));
  52.    
  53.   Expression right = Expression.Constant(value, value.GetType());
  54.    
  55.   Expression result = Expression.Call(left, typeof (string).GetMethod("Contains"), right);
  56.    
  57.   filter = Expression.And(filter, result);
  58.    
  59.   }
  60.    
  61.   }


 

 

当然,这个帮助类功能有限,如果有需要者,大家可以自己进行扩充.

本文所提到的技术,均为我师研究,因为他研究完之后就给我们讲解了原理和实现.我只是整理出来,给大家做

原文  http://www.cnblogs.com/ruhuaxiao/p/3773596.html

标签:string,param,拼接,typeof,Expression,表达式,left
From: https://www.cnblogs.com/wl-blog/p/16987995.html

相关文章