如何在不编译的情况下从现有的LambdaExpression构建LambdaExpression

sma*_*man 5 c# linq expression linq-expressions expressionvisitor

我想结合两个LambdaExpressions而不编译它们.

这就是我编译它们时的样子:

    public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
        Expression<Func<TContainer,TMember>> getMemberExpression, 
        Expression<Func<TMember,bool>> memberPredicateExpression)
    {
        return x => memberPredicateExpression.Compile()(getMemberExpression.Compile()(x));
    }
Run Code Online (Sandbox Code Playgroud)

这显然不是从提供的参数中获取目标表达式的最快方法.此外,它使它与不支持C#方法调用的LINQ to SQL等查询提供程序不兼容.

从我所看到的,似乎最好的方法是建立一个ExpressionVisitor班级.然而,这似乎是一个非常常见的任务.有谁知道现有的开源代码库提供这种功能?如果没有,最好的方法ExpressionVisitor是尽可能使其尽可能通用?

Tho*_*que 4

我不知道这是否是最好的方法,但你可以这样做:

public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
    Expression<Func<TContainer,TMember>> getMemberExpression, 
    Expression<Func<TMember,bool>> memberPredicateExpression)
{
    ParameterExpression x = Expression.Parameter(typeof(TContainer), "x");
    return Expression.Lambda<Func<TContainer, bool>>(
        Expression.Invoke(
            memberPredicateExpression,
            Expression.Invoke(
                getMemberExpression,
                x)),
        x);
}
Run Code Online (Sandbox Code Playgroud)

用法:

var expr = CreatePredicate(
    (Foo f) => f.Bar,
    bar => bar % 2 == 0);
Run Code Online (Sandbox Code Playgroud)

结果:

x => Invoke(bar => ((bar % 2) == 0), Invoke(f => f.Bar, x))
Run Code Online (Sandbox Code Playgroud)

我想得到类似的东西会更好x => x.Bar % 2 == 0,但可能会更难......


编辑:实际上对于表达式访问者来说并不难:

public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
    Expression<Func<TContainer,TMember>> getMemberExpression, 
    Expression<Func<TMember,bool>> memberPredicateExpression)
{
    return CombineExpressionVisitor.Combine(
        getMemberExpression,
        memberPredicateExpression);
}

class CombineExpressionVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _parameterToReplace;
    private readonly Expression _replacementExpression;
    private CombineExpressionVisitor(ParameterExpression parameterToReplace, Expression replacementExpression)
    {
        _parameterToReplace = parameterToReplace;
        _replacementExpression = replacementExpression;
    }

    public static Expression<Func<TSource, TResult>> Combine<TSource, TMember, TResult>(
        Expression<Func<TSource, TMember>> memberSelector,
        Expression<Func<TMember, TResult>> resultSelector)
    {
         var visitor = new CombineExpressionVisitor(
            resultSelector.Parameters[0],
            memberSelector.Body);
        return Expression.Lambda<Func<TSource, TResult>>(
            visitor.Visit(resultSelector.Body),
            memberSelector.Parameters);
    }

    protected override Expression VisitParameter(ParameterExpression parameter)
    {
        if (parameter == _parameterToReplace)
            return _replacementExpression;
        return base.VisitParameter(parameter);
    }
}
Run Code Online (Sandbox Code Playgroud)

它给出以下表达式:

f => ((f.Bar % 2) == 0)
Run Code Online (Sandbox Code Playgroud)