替换表达式正文中的参数名称

Rob*_*all 11 c# linq expression-trees

我正在尝试基于Specification对象动态构建表达式.

我创建了一个ExpressionHelper类,它有一个私有表达式,如下所示:

private Expression<Func<T, bool>> expression;

public ExpressionHelper()
{
    expression = (Expression<Func<T, bool>>)(a => true);
}
Run Code Online (Sandbox Code Playgroud)

然后一些简单的方法如下:

public void And(Expression<Func<T,bool>> exp);
Run Code Online (Sandbox Code Playgroud)

我正在和And方法的身体挣扎.我基本上想要撕掉身体exp,用那些参数替换所有参数expression然后将它附加到expression身体的末端和AndAlso.

我这样做了:

var newBody = Expression.And(expression.Body,exp.Body);

expression = expression.Update(newBody, expression.Parameters);
Run Code Online (Sandbox Code Playgroud)

但最终我的表达看起来像这样:

{ a => e.IsActive && e.IsManaged }
Run Code Online (Sandbox Code Playgroud)

有更简单的方法吗?或者我怎样才能撕掉那些e并用一个替换它们?

Mar*_*ell 21

这里最简单的方法是Expression.Invoke,例如:

public static Expression<Func<T, bool>> AndAlso<T>(
    Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(x.Body, Expression.Invoke(y, x.Parameters)),
        x.Parameters);
}
Run Code Online (Sandbox Code Playgroud)

这适用于LINQ-to-Objects和LINQ-to-SQL,但不支持EF.对于EF,你可能需要使用访问者重写树,遗憾的是.

使用以下代码:在c#中组合两个lambda表达式

public static Expression<Func<T, bool>> AndAlso<T>(
    Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
    var newY = new ExpressionRewriter().Subst(y.Parameters[0], x.Parameters[0]).Inline().Apply(y.Body);

    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(x.Body, newY),
        x.Parameters);
}
Run Code Online (Sandbox Code Playgroud)

或者在.NET 4.0中,使用ExpressionVisitor:

class ParameterVisitor : ExpressionVisitor
{
    private readonly ReadOnlyCollection<ParameterExpression> from, to;
    public ParameterVisitor(
        ReadOnlyCollection<ParameterExpression> from,
        ReadOnlyCollection<ParameterExpression> to)
    {
        if(from == null) throw new ArgumentNullException("from");
        if(to == null) throw new ArgumentNullException("to");
        if(from.Count != to.Count) throw new InvalidOperationException(
             "Parameter lengths must match");
        this.from = from;
        this.to = to;
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        for (int i = 0; i < from.Count; i++)
        {
            if (node == from[i]) return to[i];
        }
        return node;
    }
}
public static Expression<Func<T, bool>> AndAlso<T>(
      Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{
    var newY = new ParameterVisitor(y.Parameters, x.Parameters)
              .VisitAndConvert(y.Body, "AndAlso");
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(x.Body, newY),
        x.Parameters);
}
Run Code Online (Sandbox Code Playgroud)

  • 我建议断言`to.Count == from.Count`. (5认同)