123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- 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<Func<TSource, bool>> DynamicExpression<TSource>(this Expression<Func<TSource, bool>> exp,
- string propertyName, string comparer, object value)
- {
- ExpressionFactory<TSource> factory = new ExpressionFactory<TSource>();
- 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<Func<TSource, bool>>(result, paramter);
- }
- }
- public class ExpressionFactory<TSource>
- {
- private static readonly Dictionary<string, Expression> _cache = new Dictionary<string, Expression>();
- private IQueryable<TSource> _queryable;
- public Dictionary<string, Comparer> comparerDict = new Dictionary<string, Comparer>()
- {
- { "=", 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<TSource> queryable)
- {
- _queryable = queryable;
- }
- public Expression<Func<TSource, bool>> DynamicInExpression<TListType>(string propertyName, IList<TListType> 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<Func<TSource, bool>>(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<string> 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<Func<TSource, bool>> 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<Func<TSource, bool>>(result, paramter);
- }
- /// <summary>
- /// 影射的指定类型。
- /// </summary>
- /// <typeparam name="TResult"></typeparam>
- /// <returns></returns>
- public IQueryable<TResult> To<TResult>()
- {
- var selectExpression = GetSelectExpression<TResult>();
- return _queryable.Select(selectExpression);
- }
- private static Expression<Func<TSource, TResult>> GetSelectExpression<TResult>()
- {
- var key = GetKey<TResult>();
- Expression<Func<TSource, TResult>> selectExpression;
- if (_cache.ContainsKey(key))
- {
- selectExpression = _cache[key] as Expression<Func<TSource, TResult>>;
- }
- else
- {
- selectExpression = BuildExpression<TResult>();
- _cache[key] = selectExpression;
- }
- return selectExpression;
- }
- private static string GetKey<TResult>()
- {
- return string.Concat(typeof(TSource).FullName, typeof(TResult).FullName);
- }
- private static Expression<Func<TSource, TResult>> BuildExpression<TResult>()
- {
- 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<Func<TSource, TResult>>(Expression.MemberInit(Expression.New(typeof(TResult)), bindings), parameterExpression);
- return expression;
- }
- private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo resultProperty, IEnumerable<PropertyInfo> 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
- {
- /// <summary>
- /// <!-- = -->
- /// </summary>
- Equal = 0,
- /// <summary>
- /// <!-- > -->
- /// </summary>
- GreaterThan = 1,
- /// <summary>
- /// <!-- < -->
- /// </summary>
- LessThan = 2,
- /// <summary>
- /// <!-- >= -->
- /// </summary>
- GreaterThanOrEqual = 3,
- /// <summary>
- /// <!-- <= -->
- /// </summary>
- LessThanOrEqual = 4,
- /// <summary>
- /// <!-- <> -->
- /// </summary>
- NotEqual = 5,
- /// <summary>
- /// <!-- != -->
- /// </summary>
- NotEqualEx1 = 6,
- /// <summary>
- /// <!-- 左 -->
- /// </summary>
- Left = 7,
- /// <summary>
- /// <!-- 中 -->
- /// </summary>
- Contains = 8,
- /// <summary>
- /// <!-- 右 -->
- /// </summary>
- Right = 9
- }
- }
|