动态构建表达式树,最佳实践版,很实用!

 

[csharp] view plain copy
 
  1. public class FilterCollection : Collection<IList<Filter>>  
  2.    {  
  3.        public FilterCollection()  
  4.            : base()  
  5.        { }  
  6.    }  
  7.   
  8.    public class Filter  
  9.    {  
  10.        public string PropertyName { get; set; }  
  11.        public Op Operation { get; set; }  
  12.        public object Value { get; set; }  
  13.    }  
  14.   
  15.    public enum Op  
  16.    {  
  17.        Equals,  
  18.        GreaterThan,  
  19.        LessThan,  
  20.        GreaterThanOrEqual,  
  21.        LessThanOrEqual,  
  22.        Contains,  
  23.        StartsWith,  
  24.        EndsWith  
  25.    }  


通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦

 

 

[csharp] view plain copy
 
  1. using Infrastructure.Model;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Linq.Expressions;  
  6. using System.Reflection;  
  7. using System.Text;  
  8. using System.Threading.Tasks;  
  9.   
  10. namespace Infrastructure.Operation  
  11. {  
  12.     public static class LambdaExpressionBuilder  
  13.     {  
  14.         private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");  
  15.         private static MethodInfo startsWithMethod =  
  16.                                 typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });  
  17.         private static MethodInfo endsWithMethod =  
  18.                                 typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });  
  19.         private static Expression GetExpression(ParameterExpression param, Filter filter)  
  20.         {  
  21.             MemberExpression member = Expression.Property(param, filter.PropertyName);  
  22.             Expression handledMember = member;  
  23.             ConstantExpression constant = Expression.Constant(filter.Value);  
  24.   
  25.             if (member.Member.MemberType == MemberTypes.Property)  
  26.             {  
  27.                 Type propertyType = ((PropertyInfo)member.Member).PropertyType;  
  28.                 if (propertyType == typeof(string))  
  29.                 {  
  30.                     handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));  
  31.                 }  
  32.                 if (propertyType == typeof(DateTime?))  
  33.                 {  
  34.                     handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value"));  
  35.                 }  
  36.             }  
  37.   
  38.             switch (filter.Operation)  
  39.             {  
  40.                 case Op.Equals:  
  41.                     return Expression.Equal(handledMember, constant);  
  42.                 case Op.GreaterThan:  
  43.                     return Expression.GreaterThan(handledMember, constant);  
  44.                 case Op.GreaterThanOrEqual:  
  45.                     return Expression.GreaterThanOrEqual(handledMember, constant);  
  46.                 case Op.LessThan:  
  47.                     return Expression.LessThan(handledMember, constant);  
  48.                 case Op.LessThanOrEqual:  
  49.                     return Expression.LessThanOrEqual(handledMember, constant);  
  50.                 case Op.Contains:  
  51.                     return Expression.Call(handledMember, containsMethod, constant);  
  52.                 case Op.StartsWith:  
  53.                     return Expression.Call(handledMember, startsWithMethod, constant);  
  54.                 case Op.EndsWith:  
  55.                     return Expression.Call(handledMember, endsWithMethod, constant);  
  56.             }  
  57.   
  58.             return null;  
  59.         }  
  60.         private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2)  
  61.         {  
  62.             Expression bin1 = GetExpression(param, filter1);  
  63.             Expression bin2 = GetExpression(param, filter2);  
  64.   
  65.             return Expression.Or(bin1, bin2);  
  66.         }  
  67.   
  68.         private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters)  
  69.         {  
  70.             if (orFilters.Count == 0)  
  71.                 return null;  
  72.   
  73.             Expression exp = null;  
  74.   
  75.             if (orFilters.Count == 1)  
  76.             {  
  77.                 exp = GetExpression(param, orFilters[0]);  
  78.             }  
  79.             else if (orFilters.Count == 2)  
  80.             {  
  81.                 exp = GetORExpression(param, orFilters[0], orFilters[1]);  
  82.             }  
  83.             else  
  84.             {  
  85.                 while (orFilters.Count > 0)  
  86.                 {  
  87.                     var f1 = orFilters[0];  
  88.                     var f2 = orFilters[1];  
  89.   
  90.                     if (exp == null)  
  91.                     {  
  92.                         exp = GetORExpression(param, orFilters[0], orFilters[1]);  
  93.                     }  
  94.                     else  
  95.                     {  
  96.                         exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1]));  
  97.                     }  
  98.                     orFilters.Remove(f1);  
  99.                     orFilters.Remove(f2);  
  100.   
  101.                     if (orFilters.Count == 1)  
  102.                     {  
  103.                         exp = Expression.Or(exp, GetExpression(param, orFilters[0]));  
  104.                         orFilters.RemoveAt(0);  
  105.                     }  
  106.                 }  
  107.             }  
  108.   
  109.             return exp;  
  110.         }  
  111.   
  112.         public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters)  
  113.         {  
  114.             if (filters == null || filters.Count == 0)  
  115.                 return null;  
  116.   
  117.             ParameterExpression param = Expression.Parameter(typeof(T), "t");  
  118.             Expression exp = null;  
  119.   
  120.             if (filters.Count == 1)  
  121.             {  
  122.                 exp = GetExpression(param, filters[0]);  
  123.             }  
  124.             else if (filters.Count == 2)  
  125.             {  
  126.                 exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));  
  127.             }  
  128.   
  129.             else  
  130.             {  
  131.                 while (filters.Count > 0)  
  132.                 {  
  133.                     var f1 = filters[0];  
  134.                     var f2 = filters[1];  
  135.                     var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));  
  136.                     if (exp == null)  
  137.                     {  
  138.                         exp = f1Andf2;  
  139.                     }  
  140.                     else  
  141.                     {  
  142.                         exp = Expression.AndAlso(exp, f1Andf2);  
  143.                     }  
  144.   
  145.                     filters.Remove(f1);  
  146.                     filters.Remove(f2);  
  147.   
  148.                     if (filters.Count == 1)  
  149.                     {  
  150.                         exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));  
  151.                         filters.RemoveAt(0);  
  152.                     }  
  153.                 }  
  154.             }  
  155.   
  156.             return Expression.Lambda<Func<T, bool>>(exp, param);  
  157.         }  
  158.     }  
  159. }  


再来一个OrderBy动态构建

 

 

[csharp] view plain copy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Linq.Expressions;  
  5. using System.Reflection;  
  6. using System.Text;  
  7.   
  8. namespace Jurassic.Sooil.Com  
  9. {  
  10.     public static class OrderExpression  
  11.     {  
  12.         public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)  
  13.         {  
  14.             return ApplyOrder<T>(source, property, "OrderBy");  
  15.         }  
  16.         public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)  
  17.         {  
  18.             return ApplyOrder<T>(source, property, "OrderByDescending");  
  19.         }  
  20.         public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)  
  21.         {  
  22.             return ApplyOrder<T>(source, property, "ThenBy");  
  23.         }  
  24.         public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)  
  25.         {  
  26.             return ApplyOrder<T>(source, property, "ThenByDescending");  
  27.         }  
  28.         static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)  
  29.         {  
  30.             string[] props = property.Split('.');  
  31.             Type type = typeof(T);  
  32.             ParameterExpression arg = Expression.Parameter(type, "x");  
  33.             Expression expr = arg;  
  34.             foreach (string prop in props)  
  35.             {  
  36.                 // use reflection (not ComponentModel) to mirror LINQ  
  37.                 PropertyInfo pi = type.GetProperty(prop);  
  38.                 expr = Expression.Property(expr, pi);  
  39.                 type = pi.PropertyType;  
  40.             }  
  41.             Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);  
  42.             LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);  
  43.   
  44.             object result = typeof(Queryable).GetMethods().Single(  
  45.                     method => method.Name == methodName  
  46.                             && method.IsGenericMethodDefinition  
  47.                             && method.GetGenericArguments().Length == 2  
  48.                             && method.GetParameters().Length == 2)  
  49.                     .MakeGenericMethod(typeof(T), type)  
  50.                     .Invoke(null, new object[] { source, lambda });  
  51.             return (IOrderedQueryable<T>)result;  
  52.         }   
  53.     }  
  54. }  


至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!

 

不管如何,学到手的才是自己的!