Ejemplo n.º 1
0
        public ActionResult Filtrar(LivroViewModel search)
        {
            Expression <Func <Livro, bool> > filtro = null;
            Expression <Func <Livro, bool> > filtro2;

            if (search.Titulo != null)
            {
                var criterio = search.Titulo.ToLower() + "%";
                filtro2 = ent => (DbFunctions.Like(ent.Titulo.ToLower(), criterio));
                filtro  = ExpressionParameterReplacer.concatenar(filtro, filtro2);
            }

            if (search.GeneroId != null)
            {
                var criterio = search.GeneroId + "%";
                filtro2 = ent => (DbFunctions.Like(ent.GeneroId.ToString(), criterio));
                filtro  = ExpressionParameterReplacer.concatenar(filtro, filtro2);
            }

            if (search.EditoraId != null)
            {
                var criterio = search.EditoraId + "%";
                filtro2 = ent => (DbFunctions.Like(ent.EditoraId.ToString(), criterio));
                filtro  = ExpressionParameterReplacer.concatenar(filtro, filtro2);
            }

            var query = _livroAppService.ObterTodos().Where(filtro ?? (u => true));

            return(PartialView("_Resultado", query.ToList()));
        }
Ejemplo n.º 2
0
        private Func <T, bool> Compile()
        {
            Expression <Func <T, bool> > result = null;

            foreach (Rule rule in this.m_AndRules)
            {
                if (result == null)
                {
                    result = this.BuildExpression(rule);
                }
                else
                {
                    var expressionToAdd             = this.BuildExpression(rule);
                    var parameterModifiedExpression = new ExpressionParameterReplacer(expressionToAdd.Parameters, result.Parameters).Visit(expressionToAdd.Body);
                    result = Expression.Lambda <Func <T, bool> >(Expression.AndAlso(result.Body, parameterModifiedExpression), result.Parameters);
                }
            }

            foreach (Rule rule in this.m_OrRules)
            {
                if (result == null)
                {
                    result = this.BuildExpression(rule);
                }
                else
                {
                    var expressionToAdd             = this.BuildExpression(rule);
                    var parameterModifiedExpression = new ExpressionParameterReplacer(expressionToAdd.Parameters, result.Parameters).Visit(expressionToAdd.Body);
                    result = Expression.Lambda <Func <T, bool> >(Expression.OrElse(result.Body, parameterModifiedExpression), result.Parameters);
                }
            }
            return(result?.Compile());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Комбинирует  два выржанеия по заданной логике с одинаковыми входными параметрами.
        /// </summary>
        /// <typeparam name="T">Тип параметра.</typeparam>
        /// <param name="firstExpression">Первое выражение.</param>
        /// <param name="secondExpression">Второе выражени.</param>
        /// <param name="combiner">Логика комбинирования выражения. Смотрите класс <see cref="Expression"/>.</param>
        /// <returns>Скомбинированное выражение.</returns>
        public static Expression <T> CombineExpressions <T>(Expression <T> firstExpression, Expression <T> secondExpression, Func <Expression, Expression, BinaryExpression> combiner)
        {
            var left  = firstExpression.Body;
            var right = new ExpressionParameterReplacer(secondExpression.Parameters, firstExpression.Parameters).Visit(secondExpression.Body);

            var combined = Expression.Lambda <T>(combiner(firstExpression.Body, right), firstExpression.Parameters);

            return(combined);
        }
        /// <summary>
        /// Chain all expressions in the list by Or expression.
        /// </summary>
        /// <exception cref="ArgumentNullException">
        /// When expressions is null.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// When there is no expression in expressions.
        /// </exception>
        /// <typeparam name="T">Type of model.</typeparam>
        /// <param name="expressions">List of expressions to chain.</param>
        /// <returns>Constructed expression.</returns>
        public static Expression <Func <T, bool> > ConstructOrChain <T>(
            this IEnumerable <Expression <Func <T, bool> > > expressions)
        {
            if (expressions == null)
            {
                throw new ArgumentNullException("expressions");
            }
            if (expressions.Count() == 0)
            {
                throw new ArgumentOutOfRangeException(
                          "expressions",
                          "There must be at least one expression in expressions");
            }

            ParameterExpression parameterExp = Expression.Parameter(typeof(T), "m");

            Expression orChainedExpression = null;
            Expression visitedExp;

            foreach (Expression <Func <T, bool> > exp in expressions)
            {
                // Replace paremeter in expression
                ExpressionParameterReplacer parameterReplacer =
                    new ExpressionParameterReplacer(exp.Parameters.First(), parameterExp);
                visitedExp = parameterReplacer.Visit(exp.Body);

                if (orChainedExpression == null)
                {
                    orChainedExpression = visitedExp;
                }
                else
                {
                    orChainedExpression = Expression
                                          .OrElse(orChainedExpression, visitedExp);
                }
            }

            return(Expression.Lambda <Func <T, bool> >(
                       orChainedExpression, parameterExp));
        }
        public override void OnMethodCallVisit(MethodCallVisitEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            // working with static extension methods with one "this" argument and with instance methods with no arguments
            // todo: methods with multiple arguments can be implemented too
            // todo: maybe better check?
            if ((e.MethodCall.Method.IsStatic && e.MethodCall.Arguments.Count == 1) ||
                (!e.MethodCall.Method.IsStatic && e.MethodCall.Arguments.Count == 0))
            {
                var expressionAttribute = (ExpandWithExpressionAttribute)e.MethodCall.Method.GetCustomAttributes(typeof(ExpandWithExpressionAttribute), false).SingleOrDefault();

                if (expressionAttribute == null)
                {
                    throw new InvalidOperationException(String.Format(
                                                            CultureInfo.InvariantCulture,
                                                            "Method '{0}' in '{1}' class has no ExpandWithExpression attribute.",
                                                            e.MethodCall.Method.Name,
                                                            e.MethodCall.Method.DeclaringType.Name));
                }

                var declaringType = expressionAttribute.DeclaringType ?? e.MethodCall.Method.DeclaringType;
                var methodName    = expressionAttribute.MethodName ?? e.MethodCall.Method.Name;

                var expressionMethodInfo = declaringType.GetMethod(
                    methodName,
                    BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);

                if (expressionMethodInfo == null)
                {
                    throw new ArgumentException(String.Format(
                                                    CultureInfo.InvariantCulture,
                                                    "Method specified in ExpandWithExpression attribute of '{0}' method in '{1}' class is not found.",
                                                    e.MethodCall.Method.Name,
                                                    e.MethodCall.Method.DeclaringType.Name));
                }

                var customExpandedExpression = (LambdaExpression)expressionMethodInfo.Invoke(null, new object[] { this.Scope });

                // parameterExpression is object in case of instance method or single (todo: first) argument in case of extension method
                var parameterExpression = e.MethodCall.Method.IsStatic ? e.MethodCall.Arguments.Single() : e.MethodCall.Object;

                // validating custom expanded expression
                if (customExpandedExpression.Parameters.Single().Type != parameterExpression.Type ||
                    customExpandedExpression.Body.Type != e.MethodCall.Type)
                {
                    throw new InvalidOperationException(String.Format(
                                                            CultureInfo.InvariantCulture,
                                                            "Method '{0}' in '{1}' class returns invalid expression.",
                                                            expressionMethodInfo.Name,
                                                            expressionMethodInfo.DeclaringType.Name));
                }

                // localize expression (replace its parameter with local object expression)
                var localizedCustomExpandedExpression = new ExpressionParameterReplacer(
                    customExpandedExpression.Parameters.Single(),
                    parameterExpression)
                                                        .Visit(customExpandedExpression.Body);

                e.SubstituteExpression = localizedCustomExpandedExpression;
            }
        }
Ejemplo n.º 6
0
        public void TestParameterReplacer()
        {
            Expression <Func <int, int, int> > expression =
                (x, y) => x + y;

            var newParam = Expression.Parameter(typeof(int));

            //Replace Parameters

            //Typed Lambda
            var case1 = ExpressionParameterReplacer.Replace(expression, expression.Parameters[0], newParam);

            Assert.AreEqual(newParam, case1.Parameters[0]);
            Assert.AreEqual(((BinaryExpression)case1.Body).Left, newParam);

            //Untyped Lambda
            var case2 = ExpressionParameterReplacer.Replace((LambdaExpression)expression, expression.Parameters[0], newParam);

            Assert.AreEqual(newParam, case2.Parameters[0]);
            Assert.AreEqual(((BinaryExpression)case2.Body).Left, newParam);

            //Lambda as Expression
            var case3 = ExpressionParameterReplacer.Replace((Expression)expression, expression.Parameters[0], newParam);

            Assert.AreEqual(newParam, ((LambdaExpression)case3).Parameters[0]);
            Assert.AreEqual(((BinaryExpression)((LambdaExpression)case3).Body).Left, newParam);

            //Expression (no lambda)
            var case4 = ExpressionParameterReplacer.Replace(expression.Body, expression.Parameters[0], newParam);

            Assert.AreEqual(((BinaryExpression)case4).Left, newParam);

            //Replace Parameters by name

            //Typed Lambda
            var case11 = ExpressionParameterReplacer.Replace(expression, "x", newParam);

            Assert.AreEqual(newParam, case11.Parameters[0]);
            Assert.AreEqual(((BinaryExpression)case11.Body).Left, newParam);

            //Untyped Lambda
            var case12 = ExpressionParameterReplacer.Replace((LambdaExpression)expression, "x", newParam);

            Assert.AreEqual(newParam, case12.Parameters[0]);
            Assert.AreEqual(((BinaryExpression)case12.Body).Left, newParam);

            //Lambda as Expression
            var case13 = ExpressionParameterReplacer.Replace((Expression)expression, "x", newParam);

            Assert.AreEqual(newParam, ((LambdaExpression)case13).Parameters[0]);
            Assert.AreEqual(((BinaryExpression)((LambdaExpression)case13).Body).Left, newParam);

            //Expression (no lambda)
            var case14 = ExpressionParameterReplacer.Replace(expression.Body, "x", newParam);

            Assert.AreEqual(((BinaryExpression)case14).Left, newParam);

            //Replace Parameters by type, throws error because to ints

            //Untyped Lambda
            Assert.Throws <InvalidOperationException>(() => ExpressionParameterReplacer.Replace((LambdaExpression)expression, typeof(int), newParam));

            //Replace Parameters by type

            Expression <Func <int, int> > simpleExpression =
                x => x;

            //Typed Lambda
            var case21 = ExpressionParameterReplacer.Replace(simpleExpression, typeof(int), newParam);

            Assert.AreEqual(newParam, case21.Parameters[0]);
            Assert.AreEqual(case21.Body, newParam);

            //Untyped Lambda
            var case22 = ExpressionParameterReplacer.Replace((LambdaExpression)simpleExpression, typeof(int), newParam);

            Assert.AreEqual(newParam, case22.Parameters[0]);
            Assert.AreEqual(case22.Body, newParam);

            //Lambda as Expression
            var case23 = ExpressionParameterReplacer.Replace((Expression)simpleExpression, typeof(int), newParam);

            Assert.AreEqual(newParam, ((LambdaExpression)case23).Parameters[0]);
            Assert.AreEqual(((LambdaExpression)case23).Body, newParam);


            //Expression (no lambda)
            var case24 = ExpressionParameterReplacer.Replace(expression.Body, typeof(int), newParam);

            Assert.AreEqual(((BinaryExpression)case24).Left, newParam);

            //Change Type by type

            Expression <Func <A, A, bool> > expression2 =
                (x, y) => x.a > 0 && y.b > 0;

            //Untyped Lambda
            var case31 = ExpressionParameterReplacer.ChangeType((LambdaExpression)expression2, typeof(A), typeof(B));

            Assert.AreEqual(case31.Parameters[0].Type, typeof(B));

            //Lambda as Expression
            var case32 = ExpressionParameterReplacer.ChangeType((Expression)expression2, typeof(A), typeof(B));

            Assert.IsTrue(case32.GetParameters(x => x.Type == typeof(B)).Any());

            //Expression
            var case32a = ExpressionParameterReplacer.ChangeType(expression2.Body, typeof(A), typeof(B));

            Assert.IsTrue(case32a.GetParameters(x => x.Type == typeof(B)).Any());

            //Change Type by name

            //Untyped Lambda
            var case33 = ExpressionParameterReplacer.ChangeType((LambdaExpression)expression2, "x", typeof(B));

            Assert.AreEqual(case33.Parameters[0].Type, typeof(B));

            //Lambda as Expression
            var case34 = ExpressionParameterReplacer.ChangeType((Expression)expression2, "x", typeof(B));

            Assert.IsTrue(case34.GetParameters(x => x.Type == typeof(B)).Any());

            //Expression
            var case35 = ExpressionParameterReplacer.ChangeType(expression2.Body, "x", typeof(B));

            Assert.IsTrue(case35.GetParameters(x => x.Type == typeof(B)).Any());
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Gets the select expression.
        /// </summary>
        /// <param name="sourceExpression">
        /// The source expression.
        /// </param>
        /// <param name="projectionType">
        /// Type of the projection.
        /// </param>
        /// <param name="projectionConfig">
        /// The projection config.
        /// </param>
        /// <param name="projectionMemberMetadatas">
        /// The projection member metadatas.
        /// </param>
        /// <returns>
        /// The select expression from source to result via projection.
        /// </returns>
        private Expression GetSelectExpression(Expression sourceExpression, Type projectionType, object projectionConfig, IEnumerable <ProjectionMemberMetadata> projectionMemberMetadatas)
        {
            // todo: performance issues
            var resultMemberBindings = new List <MemberBinding>();

            foreach (var selectMemberMetadata in projectionMemberMetadatas)
            {
                var resultProperty = (PropertyInfo)selectMemberMetadata.Member;

                // for SelectExpression simply bind property to expression
                var expressionAttribute = selectMemberMetadata.MemberAttribute as SelectExpressionAttribute;
                if (expressionAttribute != null)
                {
                    var declaringType = expressionAttribute.DeclaringType ?? projectionType;
                    var methodName    = expressionAttribute.MethodName ?? resultProperty.Name;

                    var expressionMethod = declaringType.GetMethod(
                        methodName,
                        BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);

                    if (expressionMethod == null)
                    {
                        throw new ArgumentException(String.Format(
                                                        CultureInfo.InvariantCulture,
                                                        "Method specified in SelectExpressionMethod attribute of '{0}' property in '{1}' class is not found.",
                                                        resultProperty,
                                                        projectionType));
                    }

                    // todo: rewrite (projectionConfig is passed inside even if DeclaringType is another, works because with static methods in another DeclaringTypes projectionConfig is not used)
                    var customBindingExpression = (LambdaExpression)InvokeMethod(projectionConfig, expressionMethod, this.Scope);

                    // localize expression (replace its parameter with local sourceExpression)
                    var localizedCustomBindingExpression = new ExpressionParameterReplacer(
                        customBindingExpression.Parameters.Single(),
                        sourceExpression)
                                                           .Visit(customBindingExpression.Body);

                    // fixing up collection type if needed
                    localizedCustomBindingExpression = localizedCustomBindingExpression.FixupCollectionType(resultProperty.PropertyType);

                    resultMemberBindings.Add(Expression.Bind(resultProperty, localizedCustomBindingExpression));
                }

                // for SelectProperty there may be variants
                var propertyAttribute = selectMemberMetadata.MemberAttribute as SelectPropertyAttribute;
                if (propertyAttribute != null)
                {
                    var sourcePropertyPath       = propertyAttribute.Path ?? resultProperty.Name;
                    var sourcePropertyExpression = (Expression)sourceExpression.PropertyPath(sourcePropertyPath);

                    var sourcePropertyElementType = TypeSystem.GetElementType(sourcePropertyExpression.Type);
                    var resultPropertyElementType = TypeSystem.GetElementType(resultProperty.PropertyType);

                    // note: trying to do as much as it is possible
                    // todo: maybe do less? eg. no blind converts
                    if (sourcePropertyExpression.Type == resultProperty.PropertyType)
                    {
                        // 1. simple bind if types are equal
                        resultMemberBindings.Add(Expression.Bind(resultProperty, sourcePropertyExpression));
                    }
                    else if (resultProperty.PropertyType.IsAssignableFrom(sourcePropertyExpression.Type))
                    {
                        // 2. if types are assignable then assign with cast (which is crucial for eg. lift to null)
                        // this will cover lift to nulls (int -> int?), List<int> -> IEnumerable<int>, and some other situations
                        // but will not cover eg. some element types conversions (eg. int -> decimal)
                        var resultPropertyBindingExpression = Expression.Convert(sourcePropertyExpression, resultProperty.PropertyType);

                        resultMemberBindings.Add(Expression.Bind(resultProperty, resultPropertyBindingExpression));
                    }
                    else if (((sourcePropertyElementType == null) && (resultPropertyElementType == null)) &&
                             (sourcePropertyExpression.Type != resultProperty.PropertyType))
                    {
                        // 4-5. if both properties are not sequence types and property types are differ then it is probably an object projection or simple convert
                        if (IsProjectionFor(resultProperty.PropertyType, sourcePropertyExpression.Type))
                        {
                            // 4. object projection
                            var resultPropertyBindingExpression = this.ApplyObjectProjection(sourcePropertyExpression, resultProperty.PropertyType, null /* note: no projectionConfig here */);

                            resultMemberBindings.Add(Expression.Bind(resultProperty, resultPropertyBindingExpression));
                        }
                        else
                        {
                            // 5. simple convert
                            var resultPropertyBindingExpression = Expression.Convert(sourcePropertyExpression, resultProperty.PropertyType);

                            resultMemberBindings.Add(Expression.Bind(resultProperty, resultPropertyBindingExpression));
                        }
                    }
                    else if (((sourcePropertyElementType != null) && (resultPropertyElementType != null)) &&
                             (sourcePropertyElementType != resultPropertyElementType))
                    {
                        // 6-7. if both properties are sequence types and element types are differ then it is probably a sequence projection or sequence convert
                        if (IsProjectionFor(resultPropertyElementType, sourcePropertyElementType))
                        {
                            // 6. sequence projection
                            var resultPropertyBindingExpression = this.ApplySequenceProjection(sourcePropertyExpression, resultPropertyElementType, null /* note: no projectionConfig here */)
                                                                  .FixupCollectionType(resultProperty.PropertyType);

                            resultMemberBindings.Add(Expression.Bind(resultProperty, resultPropertyBindingExpression));
                        }
                        else
                        {
                            // 7. sequence convert: sequence.Select(element => (type) element)
                            var sourceElementParameter           = Expression.Parameter(sourcePropertyElementType, sourcePropertyElementType.Name);
                            var sourceElementConvertedExpression = Expression.Convert(sourceElementParameter, resultPropertyElementType);

                            var resultPropertyBindingExpression = sourcePropertyExpression.Select(sourceElementParameter.ToLambda(sourceElementConvertedExpression))
                                                                  .FixupCollectionType(resultProperty.PropertyType);

                            resultMemberBindings.Add(Expression.Bind(resultProperty, resultPropertyBindingExpression));
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Unknown binding of projection property. Projection {0}, property {1}.", projectionType, selectMemberMetadata.Member));
                    }
                }
            }

            var resultInitExpression = Expression.MemberInit(Expression.New(projectionType), resultMemberBindings);

            return(resultInitExpression);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Combines the first expression with the second
        /// </summary>
        /// <param name="left">Expression that accepts <c>TIn</c> and return <c>TInter</c></param>
        /// <param name="right">Expression that accepts <c>TInter</c> and return <c>TOut</c></param>
        /// <typeparam name="TIn">Input type</typeparam>
        /// <typeparam name="TInter">Intermediate type</typeparam>
        /// <typeparam name="TOut">Output type</typeparam>
        /// <returns>Expression that accepts <c>TIn</c> and return <c>TOut</c></returns>
        public static Expression <Func <TIn, TOut> > Compose <TIn, TInter, TOut>(this Expression <Func <TIn, TInter> > left, Expression <Func <TInter, TOut> > right)
        {
            var merged = new ExpressionParameterReplacer(right.Parameters[0], left.Body).Visit(right.Body);

            return(Expression.Lambda <Func <TIn, TOut> >(merged, left.Parameters[0]));
        }