用于动态对象的谓词生成器

时间:2015-06-25 14:15:17

标签: c# linq reflection expression

我有一个自制的库,可以在网格ui elemen中创建用于文件串数据的表达式 这是基本方法:

public static Expression<Func<T, bool>> GetPredicate<T>( String modelPropertyName, SearchType searchType, object data) 

查询对象非常简单。基本上,您只需要比较属性名称,运算符和数据。它使用反射为每个操作员创建表达式。

现在我要求扩展此功能.... 您可以看到此方法使用Type T.现在他们希望我更改它并将Type作为参数传递 所以新方法应该是这样的:

public static Expression<Func<object, bool>> GetPredicate(Type T , String modelPropertyName, SearchType searchType, object data) 

不知道会反对多少属性。 他们也想要使用&#34;动态&#34;对象和ExpandoObjects。那很糟糕。

我不知道我是否可以在ExpandObject中从运行时获取匿名类型。 我也不知道我是否可以回来

Expression<Func<object, bool>>

并将此表达式应用于动态对象。当然,它不能在linq中用于sql,但即使在linq中它也很难实现。

事实上,他们(从我的团队开始)正在考虑使用词典。

有人能指出我可能会有一些图书馆吗?或者也许我的方式从这个开始?

这是全班(非常有用的BTW)

namespace ###########################
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;

    public static class PredicateBuilder
    {
        #region Public  Static Methods

        /// <summary>
        ///  This is main Method of this Class It returns predicate
        ///  
        /// </summary>
        /// <typeparam name="T">Entity Type - Search Where</typeparam>
        /// <param name="modelPropertyName">property to compare (compare what)(can be nested property)</param>
        /// <param name="searchType">comparation Type (compare how)</param>
        /// <param name="data">data to compare (compare to what )</param>
        /// <returns>Able to translate to SQl predicate</returns>
        public static Expression<Func<T, bool>> GetPredicate<T>(String modelPropertyName, SearchType searchType, object data) where T : class
        {
            ParameterExpression parameterExp = Expression.Parameter(typeof(T), "t");
            MemberExpression member = Expression.PropertyOrField(parameterExp, modelPropertyName.Split('.').First());

            // If there are any dots in parram then we have to change expression 
            foreach (var innerMember in modelPropertyName.Split('.').Skip(1))
            {
                member = Expression.PropertyOrField(member, innerMember);
            }

            if (member.Type.BaseType.ToString() == "System.Enum")
            {
                data = Int32.Parse(data.ToString());
                String name = Enum.GetName(member.Type, data);
                data = Enum.Parse(member.Type, name, false);
            }
            else if (searchType != SearchType.IsIn)
            {
                switch (member.Type.ToString())
                {
                    case "System.Nullable`1[System.Int32]":
                        data = data.ToString().ToNullableInt32();
                        break;

                    case "System.Nullable`1[System.Boolean]":
                        data = data.ToString().ToNullableBoolean();
                        break;

                    case "System.Boolean":
                        data = Boolean.Parse(data.ToString());
                        break;

                    case "System.Nullable`1[System.DateTime]":
                        data = data.ToString().ToNullableDateTime();
                        break;

                    case "System.DateTime":
                        data = DateTime.Parse(data.ToString());
                        break;

                    case "System.Int32":
                        data = Int32.Parse(data.ToString());
                        break;
                }
            }
            ConstantExpression valuetoCheck;

            if (searchType == SearchType.IsIn)
            {
                valuetoCheck = Expression.Constant(data, GetListType(member.Type));
            }
            else
            {
                valuetoCheck = Expression.Constant(data, member.Type);
            }

            Expression expression = getExpression<T>(searchType, member, valuetoCheck);

            Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { parameterExp });
            return predicate;
        }

        private static Expression getExpression<T>(SearchType searchType, MemberExpression member, ConstantExpression valuetoCheck) where T : class
        {
            Expression expression;
            switch (searchType)
            {
                case SearchType.Equal:
                    expression = Equals<T>(member, valuetoCheck);
                    break;

                case SearchType.NotEqual:
                    expression = NotEquals<T>(member, valuetoCheck);
                    break;

                case SearchType.Less:
                    expression = Less<T>(member, valuetoCheck);
                    break;

                case SearchType.LessOrEqual:
                    expression = LessOrEqual<T>(member, valuetoCheck);
                    break;

                case SearchType.Greater:
                    expression = More<T>(member, valuetoCheck);
                    break;

                case SearchType.GreaterOrEqual:
                    expression = MoreorEqual<T>(member, valuetoCheck);
                    break;

                case SearchType.BeginsWith:
                    expression = BeginsWith<T>(member, valuetoCheck);
                    break;

                case SearchType.DoesNotBeginWith:
                    expression = NotBeginsWith<T>(member, valuetoCheck);
                    break;

                case SearchType.IsIn:
                    expression = IsIn<T>(member, valuetoCheck);
                    break;

                case SearchType.IsNotIn:
                    expression = NotContains<T>(member, valuetoCheck);
                    break;

                case SearchType.EndsWith:
                    expression = EndsWith<T>(member, valuetoCheck);
                    break;

                case SearchType.DoesNotEndWith:
                    expression = NotEndsWith<T>(member, valuetoCheck);
                    break;

                case SearchType.Contains:
                    expression = Contains<T>(member, valuetoCheck);
                    break;

                case SearchType.DoesNotContain:
                    expression = NotContains<T>(member, valuetoCheck);
                    break;

                case SearchType.IsNull:
                    expression = IsNull<T>(member, valuetoCheck);
                    break;

                case SearchType.IsNotNull:
                    expression = IsNotNull<T>(member, valuetoCheck);
                    break;

                default:
                    expression = Expression<Func<T, bool>>.Equal(member, valuetoCheck);
                    break;
            }
            return expression;
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> False<T>()
        {
            return f => false;
        }

        public static Expression<Func<T, bool>> True<T>()
        {
            return f => true;
        }

        public static IList CreateList(Type type)
        {
            Type genericListType = typeof(List<>).MakeGenericType(type);
            return ((IList)Activator.CreateInstance(genericListType));
        }

        public static Type GetListType(Type type)
        {
            return CreateList(type).GetType();
        }

        #endregion Public  Static Methods

        #region predicateExpressions

        private static Expression BeginsWith<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            return Expression<Func<T, bool>>.Call(member, method, valuetoCheck);
        }

        private static Expression Contains<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {

            MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            return Expression<Func<T, bool>>.Call(member, method, valuetoCheck);
        }

        private static Expression IsIn<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = GetListType(member.Type).GetMethod("Contains", new[] { member.Type }); 
            return Expression<Func<T, bool>>.Call(valuetoCheck, method, member);
        }

        private static Expression EndsWith<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
            return Expression<Func<T, bool>>.Call(member, method, valuetoCheck);
        }

        private static Expression Equals<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.Equal(member, valuetoCheck);
        }

        private static Expression IsNotNull<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.NotEqual(member, Expression.Constant(null, member.Type));
        }

        private static Expression IsNull<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.Equal(member, Expression.Constant(null, member.Type));
        }

        private static Expression Less<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.LessThan(member, valuetoCheck);
        }

        private static Expression LessOrEqual<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.LessThanOrEqual(member, valuetoCheck);
        }

        private static Expression More<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.GreaterThan(member, valuetoCheck);
        }

        private static Expression MoreorEqual<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.GreaterThanOrEqual(member, valuetoCheck);
        }

        private static Expression NotBeginsWith<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            return Expression.Not(Expression<Func<T, bool>>.Call(member, method, valuetoCheck));
        }

        private static Expression NotContains<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            return Expression.Not(Expression<Func<T, bool>>.Call(member, method, valuetoCheck));
        }

        private static Expression NotEndsWith<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            MethodInfo method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
            return Expression.Not(Expression<Func<T, bool>>.Call(member, method, valuetoCheck));
        }

        private static Expression NotEquals<T>(MemberExpression member, ConstantExpression valuetoCheck)
        {
            return Expression<Func<T, bool>>.NotEqual(member, valuetoCheck);
        }

        #endregion predicateExpressions

        #region Pivate static
        private static Boolean? ToNullableBoolean(this string s)
        {
            bool i;
            if (Boolean.TryParse(s, out i)) return i;
            return null;
        }

        private static DateTime? ToNullableDateTime(this string s)
        {
            DateTime i;
            if (DateTime.TryParse(s, out i)) return i;
            return null;
        }

        private static int? ToNullableInt32(this string s)
        {
            int i;
            if (Int32.TryParse(s, out i)) return i;
            return null;
        }
        #endregion
    }
}

0 个答案:

没有答案