在表达式主体中替换参数名称 [英] Replacing the parameter name in the Body of an Expression

查看:189
本文介绍了在表达式主体中替换参数名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据规范对象动态构建表达式.

I'm trying to dynamically build up expressions based on a Specification object.

我创建了一个ExpressionHelper类,该类具有如下私有表达式:

I've created an ExpressionHelper class that has a private Expression like so:

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

public ExpressionHelper()
{
    expression = (Expression<Func<T, bool>>)(a => true);
}

然后是一些简单的方法,如下所示:

And then some easy methods as follows:

public void And(Expression<Func<T,bool>> exp);

我正在为And方法的主体苦苦挣扎.我基本上想从exp中剥离主体,将所有参数替换为expression中的参数,然后将其与AndAlso一起附加到expression主体的末尾.

I'm struggling with the body of the And method. I basically want to rip the body out of exp, replace all the parameters with those in expression and then append it to the end of the expression body as and AndAlso.

我已经做到了:

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

expression = expression.Update(newBody, expression.Parameters);

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

But that ends up with my expression looking like this:

{ a => e.IsActive && e.IsManaged }

有没有更简单的方法可以做到这一点?或者我该如何剔除那些e并用a代替?

Is there a simpler way to do this? Or how can I rip out those e's and replace them with a's?

推荐答案

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

The simplest approach here is Expression.Invoke, for example:

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);
}

这对于LINQ-to-Objects和LINQ-to-SQL很好,但是EF不支持.遗憾的是,对于EF,您需要使用一个访问者来重写树.

This works fine for LINQ-to-Objects and LINQ-to-SQL, but isn't supported by EF. For EF you'll need to use a visitor to rewrite the tree, sadly.

使用以下代码:在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);
}

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

Or in .NET 4.0, using 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);
}

这篇关于在表达式主体中替换参数名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆