将表达式<Func <T,bool >>转换为表达式<Func <T1,bool >>,以便T是T1的成员

Bea*_*692 5 c# lambda expression-trees

我们有一个类型的实体,T1它有一个类型的成员T.这样的事情:

public class T1
{
    public T Member{get;set;}
}
Run Code Online (Sandbox Code Playgroud)

用户可以使用我们的UI为我们提供一个过滤器,我们已经将它转换为一个函数的表达式,该函数获得一个T并返回bool (Expression<Func<T,bool>>)

我想知道是否可以将其转换为获取T1并返回bool的函数的表达式.

其实我想转换这个:

(t=>t.Member1==someValue && t.Member2==someOtherValue);
Run Code Online (Sandbox Code Playgroud)

对此:

(t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);
Run Code Online (Sandbox Code Playgroud)

Gru*_*ndy 3

您可以通过几种方式做到这一点。

第一个也是最简单的:使用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);
Run Code Online (Sandbox Code Playgroud)

但在这种情况下你不会得到

t1 => (t=>(t.Member1==someValue && t.Member2==someOtherValue))(t1.Member), 
Run Code Online (Sandbox Code Playgroud)

代替

(t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);
Run Code Online (Sandbox Code Playgroud)

要替换,您可以使用ExpressionVisitor 类,例如

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

并使用它

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