using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using Bowin.Common.Linq; using System.Collections; namespace Bowin.Common.Linq.Entity { public static class ExpressionFactory { public static Expression> DynamicExpression(this Expression> exp, string propertyName, string comparer, object value) { ExpressionFactory factory = new ExpressionFactory(); Comparer comparerEnum; if (!factory.comparerDict.TryGetValue(comparer, out comparerEnum)) { throw new Exception("输入的运算符不受支持。"); } var propertyList = propertyName.Split('.').ToList(); PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyList[0]); ParameterExpression paramter = Expression.Parameter(typeof(TSource), "x"); MemberExpression property = Expression.Property(paramter, propertyList[0]); Expression result = factory.RecursiveExpression(property, propertyList.Skip(1).ToList(), comparerEnum, value); return Expression.Lambda>(result, paramter); } } public class ExpressionFactory { private static readonly Dictionary _cache = new Dictionary(); private IQueryable _queryable; public Dictionary comparerDict = new Dictionary() { { "=", Comparer.Equal }, { ">", Comparer.GreaterThan }, { "<", Comparer.LessThan }, { ">=", Comparer.GreaterThanOrEqual }, { "<=", Comparer.LessThanOrEqual }, { "<>", Comparer.NotEqual }, { "!=", Comparer.NotEqualEx1 }, { "左", Comparer.Left }, { "中", Comparer.Contains }, { "右", Comparer.Right } }; public ExpressionFactory() { } public ExpressionFactory(IQueryable queryable) { _queryable = queryable; } public Expression> DynamicInExpression(string propertyName, IList valueList) { PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyName); ParameterExpression paramter = Expression.Parameter(typeof(TSource), "x"); MemberExpression property = Expression.Property(paramter, propertyName); var method = valueList.GetType().GetMethod("Contains"); Expression result; result = Expression.Call(Expression.Constant(valueList), method, property); return Expression.Lambda>(result, paramter); } private Expression ParseValue(object value, Type propertyType) { if (value.GetType().Name.StartsWith("String") && !propertyType.Name.StartsWith("String")) { return Expression.Convert(Expression.Constant(value.ToString().ParseToType(propertyType)), propertyType); } else { try { return Expression.Convert(Expression.Constant(value), propertyType); } catch (Exception ex) { return Expression.Convert(Expression.Constant(null), propertyType); } } } public Expression RecursiveExpression(Expression parent, List propertyList, Comparer comparerEnum, object value) { Type propertyType; if (parent is MemberExpression) { propertyType = ((PropertyInfo)(((MemberExpression)parent).Member)).PropertyType; } else { propertyType = ((ParameterExpression)parent).Type; } if (typeof(IEnumerable).IsAssignableFrom(propertyType) && !propertyType.Name.StartsWith("String")) { var anyMethods = typeof(Enumerable).GetMethods().Where(x => x.Name == "Any"); var anyMethod = anyMethods.FirstOrDefault(x => x.GetParameters().Length == 2); var elementType = propertyType.GetGenericArguments().FirstOrDefault(); anyMethod = anyMethod.MakeGenericMethod(elementType); ParameterExpression paramter = Expression.Parameter(elementType); if (propertyList.Count > 0) { var anyExpression = RecursiveExpression( Expression.Property(paramter, elementType.GetProperty(propertyList[0])), propertyList.Skip(1).ToList(), comparerEnum, value); return Expression.Call(anyMethod, parent, Expression.Lambda(anyExpression, paramter)); } else { return Expression.Call(parent, anyMethod, Expression.Equal(paramter, this.ParseValue(value, elementType))); } } else if (!(propertyType.IsValueType || propertyType.Name.StartsWith("String"))) { return RecursiveExpression(parent, propertyList.Skip(1).ToList(), comparerEnum, value); } else { MemberExpression property = (MemberExpression)parent; PropertyInfo propertyInfo = (PropertyInfo)(property.Member); Expression valueExp = this.ParseValue(value, propertyInfo.PropertyType); Expression result; switch (comparerEnum) { case Comparer.Equal: if (propertyInfo.PropertyType.FullName.Contains("System.DateTime")) { DateTime tmp; if (value == null) { result = Expression.Equal(property, valueExp); } else { tmp = DateTime.Parse(value.ToString()); if (tmp.Hour == 0 && tmp.Minute == 0 && tmp.Second == 0 && tmp.Millisecond == 0) //判断是否有值并且只剩下日期部分 { result = Expression.And(Expression.GreaterThanOrEqual(property, valueExp), Expression.LessThan(property, this.ParseValue(tmp.AddDays(1), propertyInfo.PropertyType))); } else { result = Expression.Equal(property, valueExp); } } } else { result = Expression.Equal(property, valueExp); } break; case Comparer.GreaterThan: if (propertyInfo.PropertyType.Name.StartsWith("String")) { Expression propertyExpression = Expression.Call( property, typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) }), Expression.Constant(value)); result = Expression.GreaterThan(propertyExpression, Expression.Constant(0)); } else { result = Expression.GreaterThan(property, valueExp); } break; case Comparer.LessThan: if (propertyInfo.PropertyType.Name.StartsWith("String")) { Expression propertyExpression = Expression.Call( property, typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) }), Expression.Constant(value)); result = Expression.LessThan(propertyExpression, Expression.Constant(0)); } else { result = Expression.LessThan(property, valueExp); } break; case Comparer.GreaterThanOrEqual: if (propertyInfo.PropertyType.Name.StartsWith("String")) { Expression propertyExpression = Expression.Call( property, typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) }), Expression.Constant(value)); result = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(0)); } else { result = Expression.GreaterThanOrEqual(property, valueExp); } break; case Comparer.LessThanOrEqual: if (propertyInfo.PropertyType.Name.StartsWith("String")) { Expression propertyExpression = Expression.Call( property, typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) }), Expression.Constant(value)); result = Expression.LessThanOrEqual(propertyExpression, Expression.Constant(0)); } else { result = Expression.LessThanOrEqual(property, valueExp); } break; case Comparer.NotEqual: case Comparer.NotEqualEx1: result = Expression.NotEqual(property, valueExp); break; case Comparer.Left: if (propertyInfo.PropertyType.Name.StartsWith("String")) { if (value != null) { result = Expression.Call( property, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(value)); } else { result = Expression.Constant(true); } } else { throw new Exception("只有字符串属性才可以使用‘左’、‘中’、‘右’操作符。"); } break; case Comparer.Contains: if (propertyInfo.PropertyType.Name.StartsWith("String")) { if (value != null) { result = Expression.Call( property, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(value)); } else { result = Expression.Constant(true); } } else { throw new Exception("只有字符串属性才可以使用‘左’、‘中’、‘右’操作符。"); } break; case Comparer.Right: if (propertyInfo.PropertyType.Name.StartsWith("String")) { if (value != null) { result = Expression.Call( property, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), Expression.Constant(value)); } else { result = Expression.Constant(true); } } else { throw new Exception("只有字符串属性才可以使用‘左’、‘中’、‘右’操作符。"); } break; default: throw new Exception("输入的运算符不受支持。"); } return result; } } public Expression> DynamicExpression(string propertyName, string comparer, object value) { Comparer comparerEnum; if (!comparerDict.TryGetValue(comparer, out comparerEnum)) { throw new Exception("输入的运算符不受支持。"); } var propertyList = propertyName.Split('.').ToList(); PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyList[0]); ParameterExpression paramter = Expression.Parameter(typeof(TSource), "x"); MemberExpression property = Expression.Property(paramter, propertyList[0]); Expression result = RecursiveExpression(property, propertyList.Skip(1).ToList(), comparerEnum, value); return Expression.Lambda>(result, paramter); } /// /// 影射的指定类型。 /// /// /// public IQueryable To() { var selectExpression = GetSelectExpression(); return _queryable.Select(selectExpression); } private static Expression> GetSelectExpression() { var key = GetKey(); Expression> selectExpression; if (_cache.ContainsKey(key)) { selectExpression = _cache[key] as Expression>; } else { selectExpression = BuildExpression(); _cache[key] = selectExpression; } return selectExpression; } private static string GetKey() { return string.Concat(typeof(TSource).FullName, typeof(TResult).FullName); } private static Expression> BuildExpression() { var sourceProperties = typeof(TSource).GetProperties(); var resultProperties = typeof(TResult).GetProperties().Where(w => w.CanWrite); var parameterExpression = Expression.Parameter(typeof(TSource), "source"); var bindings = resultProperties.Select(s => BuildBinding(parameterExpression, s, sourceProperties)).Where(w => w != null); var expression = Expression.Lambda>(Expression.MemberInit(Expression.New(typeof(TResult)), bindings), parameterExpression); return expression; } private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo resultProperty, IEnumerable sourceProperties) { var sourceProperty = sourceProperties.FirstOrDefault(w => w.Name == resultProperty.Name); var propertyNames1 = SplitCamelCase(resultProperty.Name); if (sourceProperty != null) { return Expression.Bind(resultProperty, Expression.Property(parameterExpression, sourceProperty)); } var propertyNames = SplitCamelCase(resultProperty.Name); if (propertyNames.Length == 2) { sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]); if (sourceProperty != null) { var sourceChildProperty = sourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]); if (sourceChildProperty != null) { return Expression.Bind(resultProperty, Expression.Property(Expression.Property(parameterExpression, sourceProperty), sourceChildProperty)); } } } return null; } private static string[] SplitCamelCase(string input) { var ss = Regex.Replace(input, "([A-Z])", " $1"); return Regex.Replace(input, "([A-Z])", " $1").Trim().Split(' '); } } public enum Comparer { /// /// /// Equal = 0, /// /// /// GreaterThan = 1, /// /// /// LessThan = 2, /// /// /// GreaterThanOrEqual = 3, /// /// /// LessThanOrEqual = 4, /// /// /// NotEqual = 5, /// /// /// NotEqualEx1 = 6, /// /// /// Left = 7, /// /// /// Contains = 8, /// /// /// Right = 9 } }