Search code examples
c#lambdaexpression-trees

Convert an Expression<Func<T,bool>> to an Expression<Func<T1,bool>> so that T is a member of T1


We have an entity of type T1 which has a member of type T. something like this :

public class T1
{
    public T Member{get;set;}
}

User can use our UI to give us a filter over T and we have translate it to an expression of a function that gets a T and returns bool (Expression<Func<T,bool>>)

I would like to know is it possible to convert this to an expression of a function that gets T1 and returns bool.

Actually I'd like to convert this :

(t=>t.Member1==someValue && t.Member2==someOtherValue);

to this :

(t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);

Solution

  • You can do it with a few way.

    First and simplest: use Expression.Invoke

    Expression<Func<T, bool>> exprT = t.Member1==someValue && t.Member2==someOtherValue
    ParameterExpression p = Expression.Parameter(typeof(T1));
    var expr = Expression.Invoke(expr, Expression.PropertyOrField(p, "Member"));
    Expression<Func<T1, bool>> exprT1 = Expression.Lambda<Func<T1, bool>>(expr, p);
    

    but in this case you get not

    t1 => (t=>(t.Member1==someValue && t.Member2==someOtherValue))(t1.Member), 
    

    instead of

    (t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);
    

    For replacing you can use ExpressionVisitor class like

        class V : ExpressionVisitor
        {
            public ParameterExpression Parameter { get; private set; }
            Expression m;
            public V(Type parameterType, string member)
            {
                Parameter = Expression.Parameter(parameterType);
                this.m = Expression.PropertyOrField(Parameter, member);
            }
            protected override Expression VisitParameter(ParameterExpression node)
            {
                if (node.Type == m.Type)
                {
                    return m;
                }
                return base.VisitParameter(node);
            }
        }
    

    and use it

    var v = new V(typeof(T1), "Member");
    var exprT1 = Expression.Lambda<Func<T1, bool>>(v.Visit(exprT.Body), v.Parameter);