0

I faced a little bit problem with Expression<>.

Is it possible to combine more than 2 expression in to one? Example:

Expression<Func<Event, bool>> searchForLogCorrelationKeyExpression =
            x => string.Equals(x.LOG_CORR_KEY, model.CorrelationKey, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLsidExpressionExpression =
            x => string.Equals(x.LOG_LSID, model.LsId, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLogLocationExpression =
            x => string.Equals(x.LOG_LOCATION, model.LogLocation, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLogTypeExpression =
            x => string.Equals(x.LOG_TP, model.LogType.ToString(), StringComparison.CurrentCultureIgnoreCase);
        if (model.EndDateTime != null && model.StartDateTime != null)
        {
            Expression<Func<Event, bool>> searchForLogInDateRangeExpression =
                x => model.StartDateTime <= x.LOG_TS && model.EndDateTime <= x.LOG_TS;
        }   
        Expression<Func<Event, bool>> searchForLogByUserIdExpression =
            x => string.Equals(x.LOG_USERID, model.UserId.ToString(), StringComparison.CurrentCultureIgnoreCase);

        Expression<Func<Event, bool>> searchForLogByLogTextExpression =
            x => string.Equals(x.LOG_TXT, model.SearchString.ToString(), StringComparison.CurrentCultureIgnoreCase);

I have 7 expressions that I want to combine in to one and then put it to the method that accepts Expression<Func<Event, bool>> as a parameter.

Is it possible? I found many example with combining two expressions but they didn't work.

Daniil T.
  • 1,145
  • 2
  • 13
  • 33
  • Have you tried var body = Expression.AndAlso(expr1.Body, expr2.Body); in a loop? – MistyK Jun 11 '17 at 17:47
  • 1
    What do you mean by *they didn't work*. Every predicate builder helper will work - [Universal Predicate Builder](https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/), [my own](https://stackoverflow.com/questions/36246162/establish-a-link-between-two-lists-in-linq-to-entities-where-clause/36247259#36247259), the famous [PredicateBuilder](http://www.albahari.com/nutshell/predicatebuilder.aspx) etc. – Ivan Stoev Jun 11 '17 at 17:48
  • @MistyK As I know it may take only to arguments/Expressions. I need to put 7 expressions. Or do missing something in your idea ? – Daniil T. Jun 11 '17 at 17:58
  • @IvanStoev Those example are based on two expressions as all others. I need to put somehow seven expressions in to one. Or maybe I don't understand something in those examples. – Daniil T. Jun 11 '17 at 18:01
  • They can be chained - `expr1.And(expr2).And(expr3).And(expr4)...` – Ivan Stoev Jun 11 '17 at 18:04
  • @IvanStoev to which link you are referring? Maybe you could post and example and will accept it as an answer? Because based on your comment I don't get such extension as And() on Expression. Or probably I'm doing something wrong. – Daniil T. Jun 11 '17 at 19:01

1 Answers1

1

Fiddle: https://dotnetfiddle.net/V7Ol0J

Source of knowledge: https://www.codeproject.com/Articles/895951/Combining-expressions-to-dynamically-append-criter

Here is a working example:

   public class Event
    {
        public string A {get;set;}
        public string B {get;set;}
        public string C {get;set;}
    }




public static class Extensions
{
    public static Expression<Func<T, Boolean>> AndAlso<T>(this Expression<Func<T, Boolean>> left, Expression<Func<T, Boolean>> right)
        {
            Expression<Func<T, Boolean>> combined = Expression.Lambda<Func<T, Boolean>>(
                Expression.AndAlso(
                    left.Body,
                    new ExpressionParameterReplacer(right.Parameters, left.Parameters).Visit(right.Body)
                    ), left.Parameters);

                     return combined;
        }
    }



    public class ExpressionParameterReplacer : ExpressionVisitor
    {
        private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements { get; set; }

        public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
        {
            ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();

            for(int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
            { ParameterReplacements.Add(fromParameters[i], toParameters[i]); }
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            ParameterExpression replacement;

            if(ParameterReplacements.TryGetValue(node, out replacement))
            { node = replacement; }

            return base.VisitParameter(node);
        }           
    }

Usage:

            Expression<Func<Event, bool>> searchForLogCorrelationKeyExpression = x => string.Equals(x.A, "A", StringComparison.CurrentCultureIgnoreCase);
            Expression<Func<Event, bool>> searchForLsidExpressionExpression =  x => string.Equals(x.B, "B", StringComparison.CurrentCultureIgnoreCase);
            Expression<Func<Event, bool>> searchForLogLocationExpression = x => string.Equals(x.C, "C", StringComparison.CurrentCultureIgnoreCase);

            var res = searchForLogCorrelationKeyExpression.AndAlso(searchForLsidExpressionExpression).AndAlso(searchForLogLocationExpression);

            Console.WriteLine(res.Compile()(new Event(){A="A",B="B",C="C"}));
MistyK
  • 6,055
  • 2
  • 42
  • 76