zoukankan      html  css  js  c++  java
  • 根据表达式树动态生成Lambda表达式

    1.准备

    1. 环境:Asp.Net MVC5 、EF6
    2. 前置知识:反射、使用过EF编写过Lambda表达式

    2.基础类库

    2.1该高级条件的类型

     1     /// <summary>
     2     /// 当前条件所属类型
     3     /// </summary>
     4     public enum Em_AS_ConditionType
     5     {
     6         /// <summary>
     7         /// 8         /// </summary>
     9         [Description("")]
    10         And = 0,
    11 
    12         /// <summary>
    13         ///14         /// </summary>
    15         [Description("")]
    16         Or = 1
    17     }

    2.2搜索条件

     1     /// <summary>
     2     /// 高级搜索条件
     3     /// </summary>
     4     public enum Em_AS_Condition
     5     {
     6         /// <summary>
     7         /// 包含
     8         /// </summary>
     9         [Description("包含")]
    10         Include = 0,
    11 
    12         /// <summary>
    13         /// 等于
    14         /// </summary>
    15         [Description("=")]
    16         Equal = 1,
    17 
    18         /// <summary>
    19         /// 大于等于
    20         /// </summary>
    21         [Description(">=")]
    22         GtEqual = 2,
    23 
    24         /// <summary>
    25         /// 大于
    26         /// </summary>
    27         [Description(">")]
    28         Gt = 3,
    29 
    30         /// <summary>
    31         /// 小于等于
    32         /// </summary>
    33         [Description("<=")]
    34         LtEqual = 4,
    35 
    36         /// <summary>
    37         /// 小于
    38         /// </summary>
    39         [Description("<")]
    40         Lt = 5,
    41     }

    2.3前端传来的数据模型格式

        /// <summary>
        /// 高级查询
        /// </summary>public class QM_Adv
        {
            /// <summary>
            /// 属性名称
            /// </summary>public string PropName { get; set; }
    
            /// <summary>
            /// 条件
            /// </summary>public Em_AS_Condition Condition { get; set; }
    
            /// <summary>
            /// 关键字
            /// </summary>public string Keyword { get; set; }
    
            /// <summary>
            /// 这组条件与其它条件的关系
            /// </summary>public Em_AS_ConditionType ConditionType { get; set; }
        }

    3.准备好基础类库,然后就可以编写表达式树生成Lambda的代码了

    3.1.表达式的种类

    1. BinaryExpression
    2. MethodCallExpression
    3.1.1:BinaryExpression: 生成的lambda如:
    p=>p.Age==21
    p=>p.Age<=21
    p=>p.Age!=21
     3.1.2:MethodCallExpression:生成的lambda如
    p=>p.Name.Contains("陈")
    

     3.2方法介绍

    3.2.1:Expression.Constant(object value) 创建一个常数表达式,一般方在表达式的右边;也可同时放在表达式的两边组成一个恒为真、恒为假的表达式

    3.2.2:Expression.Property(ParameterExpression pe, string propertyName) 访问字段或属性,一般放在表达式左边;生成的表示式就是上面中的p=>p.Age,p=>p.Name

    3.2.3:Expression.Call(Expression instance,MethodInfo method,Expression[] arguments) 返回一个MethodCallExpression

    3.2.4:Expression.Equal(Expression left, Expression right) 返回两边相等的BinaryExpression如:p=>p.Age==21
    3.2.5:还有很多类似与Expression.Equal这个方法的,可查阅https://msdn.microsoft.com/zh-cn/library/system.linq.expressions.expression(v=vs.110).aspx

    3.3 示例代码

    3.3.1:类库

      1         /// <summary>
      2         /// 恒为真
      3         /// </summary>
      4         /// <returns>表达式</returns>
      5         public static Expression EqualTrueCompare()
      6         {
      7             var type = typeof(string);
      8             var pRef = Expression.Constant(true);
      9             var constantReference = Expression.Constant(true);
     10             var be = Expression.Equal(pRef, constantReference);
     11             return be;
     12         }
     13 
     14         /// <summary>
     15         /// 包含
     16         /// </summary>
     17         /// <typeparam name="TSource">数据类型</typeparam>
     18         /// <param name="pe">左侧表达式参数</param>
     19         /// <param name="property">属性</param>
     20         /// <param name="value"></param>
     21         /// <returns>表达式</returns>
     22         public static Expression IncludeCompare<TSource>(ParameterExpression pe, string property, object value)
     23         {
     24             try
     25             {
     26                 var type = typeof(TSource);
     27                 object val = null;
     28                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
     29                 if (val == null) return null;
     30                 var propertyReference = Expression.Property(pe, property);
     31                 var constantReference = Expression.Constant(val, dyType);
     32                 var be = Expression.Call(propertyReference, typeof(string).GetMethod("Contains"), constantReference);
     33                 return be;
     34             }
     35             catch (Exception e)
     36             {
     37                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
     38                 return null;
     39             }
     40         }
     41 
     42         /// <summary>
     43         /// 等于
     44         /// </summary>
     45         /// <typeparam name="TSource">数据类型</typeparam>
     46         /// <param name="pe">左侧表达式参数</param>
     47         /// <param name="property">属性</param>
     48         /// <param name="value"></param>
     49         /// <returns>表达式</returns>
     50         public static Expression EqualCompare<TSource>(ParameterExpression pe, string property, object value)
     51         {
     52             try
     53             {
     54                 var type = typeof(TSource);
     55                 object val = null;
     56                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
     57                 if (val == null) return null;
     58                 var propertyReference = Expression.Property(pe, property);
     59                 var constantReference = Expression.Constant(val, dyType);
     60                 BinaryExpression be = Expression.Equal(propertyReference, constantReference);
     61                 return be;
     62             }
     63             catch (Exception e)
     64             {
     65                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
     66                 return null;
     67             }
     68         }
     69 
     70         /// <summary>
     71         /// 大于等于
     72         /// </summary>
     73         /// <typeparam name="TSource">数据类型</typeparam>
     74         /// <param name="pe">左侧表达式参数</param>
     75         /// <param name="property">属性</param>
     76         /// <param name="value"></param>
     77         /// <returns>表达式</returns>
     78         public static Expression GtEqualCompare<TSource>(ParameterExpression pe, string property, object value)
     79         {
     80             try
     81             {
     82                 var type = typeof(TSource);
     83                 object val = null;
     84                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
     85                 if (val == null) return null;
     86                 var propertyReference = Expression.Property(pe, property);
     87                 var constantReference = Expression.Constant(val, dyType);
     88                 BinaryExpression be = Expression.GreaterThanOrEqual(propertyReference, constantReference);
     89                 return be;
     90             }
     91             catch (Exception e)
     92             {
     93                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
     94                 return null;
     95             }
     96         }
     97 
     98         /// <summary>
     99         /// 大于
    100         /// </summary>
    101         /// <typeparam name="TSource">数据类型</typeparam>
    102         /// <param name="pe">左侧表达式参数</param>
    103         /// <param name="property">属性</param>
    104         /// <param name="value"></param>
    105         /// <returns>表达式</returns>
    106         public static Expression GtCompare<TSource>(ParameterExpression pe, string property, object value)
    107         {
    108             try
    109             {
    110                 var type = typeof(TSource);
    111                 object val = null;
    112                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
    113                 if (val == null) return null;
    114                 var propertyReference = Expression.Property(pe, property);
    115                 var constantReference = Expression.Constant(val, dyType);
    116                 BinaryExpression be = Expression.GreaterThan(propertyReference, constantReference);
    117                 return be;
    118             }
    119             catch (Exception e)
    120             {
    121                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
    122                 return null;
    123             }
    124         }
    125 
    126         /// <summary>
    127         /// 小于等于
    128         /// </summary>
    129         /// <typeparam name="TSource">数据类型</typeparam>
    130         /// <param name="pe">左侧表达式参数</param>
    131         /// <param name="property">属性</param>
    132         /// <param name="value"></param>
    133         /// <returns>表达式</returns>
    134         public static Expression LtEqualCompare<TSource>(ParameterExpression pe, string property, object value)
    135         {
    136             try
    137             {
    138                 var type = typeof(TSource);
    139                 object val = null;
    140                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
    141                 if (val == null) return null;
    142                 var propertyReference = Expression.Property(pe, property);
    143                 var constantReference = Expression.Constant(val, dyType);
    144                 BinaryExpression be = Expression.LessThanOrEqual(propertyReference, constantReference);
    145                 return be;
    146             }
    147             catch (Exception e)
    148             {
    149                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
    150                 return null;
    151             }
    152         }
    153 
    154         /// <summary>
    155         /// 小于
    156         /// </summary>
    157         /// <typeparam name="TSource">数据类型</typeparam>
    158         /// <param name="pe">左侧表达式参数</param>
    159         /// <param name="property">属性</param>
    160         /// <param name="value"></param>
    161         /// <returns>表达式</returns>
    162         public static Expression LtCompare<TSource>(ParameterExpression pe, string property, object value)
    163         {
    164             try
    165             {
    166                 var type = typeof(TSource);
    167                 object val = null;
    168                 Type dyType = TypeConvert.GetValue(type, property, value, out val);
    169                 if (val == null) return null;
    170                 var propertyReference = Expression.Property(pe, property);
    171                 var constantReference = Expression.Constant(val, dyType);
    172                 BinaryExpression be = Expression.LessThan(propertyReference, constantReference);
    173                 return be;
    174             }
    175             catch (Exception e)
    176             {
    177                 LogHelper.WriteLog("表达式树生成错误,此条件将被忽略=>" + e.Message, e);
    178                 return null;
    179             }
    180         }

    3.3.2:TypeConvert.cs

      1         /// <summary>
      2         /// 根据实体类动态转换值类型,并输出转换后的值
      3         /// </summary>
      4         /// <param name="type">实体类型</param>
      5         /// <param name="propName">属性名</param>
      6         /// <param name="value">原始值</param>
      7         /// <param name="oVal">输出值</param>
      8         /// <returns>该属性对应的数据类型</returns>
      9         public static Type GetValue(Type type, string propName, object value, out object oVal)
     10         {
     11             Type objType = null;
     12             object objValue = null;
     13             foreach (var pi in type.GetProperties())
     14             {
     15                 if (pi.Name == propName)
     16                 {
     17                     objType = pi.PropertyType;
     18                     string typeStr = string.Empty;
     19                     bool isNullType = IsNullableType(pi.PropertyType);
     20                     if (isNullType)
     21                     {
     22                         typeStr = pi.PropertyType.GetGenericArguments()[0].Name.ToLower();
     23                     }
     24                     else
     25                     {
     26                         typeStr = pi.PropertyType.Name.ToLower();
     27                     }
     28                     switch (typeStr)
     29                     {
     30                         case "string":
     31                             objValue = value + "";
     32                             break;
     33                         case "datetime":
     34                             DateTime tempDateTime;
     35                             bool isDateTime = DateTime.TryParse(value + "", out tempDateTime);
     36                             if (isDateTime)
     37                             {
     38                                 objValue = tempDateTime;
     39                             }
     40                             else
     41                             {
     42                                 objValue = null;
     43                             }
     44                             break;
     45                         case "int16":
     46                         case "int32":
     47                         case "int64":
     48                             int tempint = 0;
     49                             bool isInt = int.TryParse(value + "", out tempint);
     50                             if (isInt)
     51                             {
     52                                 objValue = tempint;
     53                             }
     54                             else
     55                             {
     56                                 objValue = null;
     57                             }
     58                             break;
     59                         case "double":
     60                             double tempDouble = 0;
     61                             var tempStrDouble = value + "";
     62                             bool isDouble = double.TryParse(tempStrDouble, out tempDouble);
     63                             if (isDouble)
     64                             {
     65                                 objValue = tempDouble;
     66                             }
     67                             else
     68                             {
     69                                 objValue = null;
     70                             }
     71                             break;
     72                         case "decimal":
     73                             decimal tempDecimal = 0;
     74                             var tempStr = value + "";
     75                             bool isdecimal = decimal.TryParse(tempStr, out tempDecimal);
     76                             if (isdecimal)
     77                             {
     78                                 objValue = tempDecimal;
     79                             }
     80                             else
     81                             {
     82                                 objValue = null;
     83                             }
     84                             break;
     85                         default:
     86 
     87                             break;
     88                     }
     89                 }
     90             }
     91             oVal = objValue;
     92             return objType;
     93         }
     94 
     95         /// <summary>
     96         /// 判定是否为可空类型
     97         /// </summary>
     98         /// <param name="theType">类型</param>
     99         /// <returns></returns>
    100         public static bool IsNullableType(Type theType)
    101         {
    102             return (theType.IsGenericType && theType.GetGenericTypeDefinition() == typeof(Nullable<>));
    103         }

    3.4:将多个查询条件转换成表达式树

     1         /// <summary>
     2         /// 将高级查询转换成对应的表达式树
     3         /// </summary>
     4         /// <typeparam name="TSource">类型</typeparam>
     5         /// <param name="conditions">高级查询条件集合</param>
     6         /// <returns>对象数据类型的表达式树</returns>
     7         public static Expression<Func<TSource, bool>> ConvertToExpression<TSource>(this List<QM_Adv> conditions)
     8         {
     9             var type = typeof(TSource);
    10             var pe = Expression.Parameter(type, "p");
    11 
    12             Expression exp = null;
    13             if (conditions == null)
    14             {
    15                 exp = ExpressionLib.EqualTrueCompare();
    16                 return Expression.Lambda<Func<TSource, bool>>(exp, pe);
    17             }
    18             //并:生成交集的条件
    19             conditions.Where(p => p.ConditionType == Em_AS_ConditionType.And).ToList().ForEach(p =>
    20             {
    21                 Expression temp = GetExpressionTemp<TSource>(p, pe);
    22                 if (exp == null)
    23                 {
    24                     if (temp != null)
    25                     {
    26                         exp = temp;
    27                     }
    28                 }
    29                 else
    30                 {
    31                     if (temp != null)
    32                     {
    33                         exp = Expression.AndAlso(exp, temp);
    34                     }
    35                 }
    36             });
    37 
    38             //或:生成并集的条件
    39             conditions.Where(p => p.ConditionType == Em_AS_ConditionType.Or).ToList().ForEach(p =>
    40             {
    41                 Expression temp = GetExpressionTemp<TSource>(p, pe);
    42                 if (exp == null)
    43                 {
    44                     if (temp != null)
    45                     {
    46                         exp = temp;
    47                     }
    48                 }
    49                 else
    50                 {
    51                     if (temp != null)
    52                     {
    53                         exp = Expression.Or(exp, temp);
    54                     }
    55                 }
    56             });
    57             if (exp == null)
    58             {
    59                 exp = ExpressionLib.EqualTrueCompare();
    60             }
    61 
    62             return Expression.Lambda<Func<TSource, bool>>(exp, pe);
    63         }
    64 
    65         private static Expression GetExpressionTemp<TSource>(QM_Adv p, ParameterExpression pe)
    66         {
    67             Expression temp = null;
    68             switch (p.Condition)
    69             {
    70                 case Em_AS_Condition.Include:
    71                     temp = ExpressionLib.IncludeCompare<TSource>(pe, p.PropName, p.Keyword);
    72                     break;
    73                 case Em_AS_Condition.GtEqual:
    74                     temp = ExpressionLib.GtEqualCompare<TSource>(pe, p.PropName, p.Keyword);
    75                     break;
    76                 case Em_AS_Condition.Gt:
    77                     temp = ExpressionLib.GtCompare<TSource>(pe, p.PropName, p.Keyword);
    78                     break;
    79                 case Em_AS_Condition.LtEqual:
    80 
    81                     temp = ExpressionLib.LtEqualCompare<TSource>(pe, p.PropName, p.Keyword);
    82                     break;
    83                 case Em_AS_Condition.Lt:
    84                     temp = ExpressionLib.LtCompare<TSource>(pe, p.PropName, p.Keyword);
    85                     break;
    86                 case Em_AS_Condition.Equal:
    87                     temp = ExpressionLib.EqualCompare<TSource>(pe, p.PropName, p.Keyword);
    88                     break;
    89                 default:
    90                     break;
    91             }
    92             return temp;
    93         }

    4.1最后结语

    这是我第一次写博客,能力有限,有不对的地方欢迎指出

  • 相关阅读:
    啥叫ORM
    git reset --hard HEAD^ 在cmd中执行报错
    windows下生成文件目录树
    批量解决win10图标上有两个蓝色箭头的方法
    Sublime Text 3 安装包
    Sublime Text 3 部分安装过程记录
    sense8影评摘抄
    如何取消chrome的自动翻译
    把本地仓库同步到github上去
    关于PDF阅读器
  • 原文地址:https://www.cnblogs.com/impl/p/6882148.html
Copyright © 2011-2022 走看看