使用不同的参数为另一个创建表达式

时间:2018-04-08 02:17:41

标签: c# entity-framework-6 expression

如果Expression包含X Expression,是否可以创建从Y收到X类型的Y来接收public class Y { public int Something { get; set; } } public class X { public Y Y { get; set; } } 类型在里面?

例如,我有以下类型:

Y

我们说这个函数返回Expression private static Expression<Func<Y, bool>> ExprY(Y y2) { return y1 => y1.Something == y2.Something; }

Y

如您所见,我可以向此函数发送Expression<Func<Y, bool>>个对象,它将返回Expression

现在,让我们说我想创建相同的X但是来自private static Expression<Func<X, bool>> ExprX(X x2) { return x1 => x1.Y.Something == x2.Y.Something; } ,这样我就可以这样写:

Something

这很好用,但我复制代码,因为比较ExprX的内容与两个函数内部相同,所以问题是如何重写ExprY以某种方式在其内部使用Something所以我不需要重复public static Expression<Func<X, bool>> ExprX(X x2) { return x1 => ExprY(x2.Y)(x1.Y); } 比较?

类似的东西:

.Where

PS。这是由实体框架6在RUN apt-get install -y locales RUN locale-gen en_US.UTF-8 RUN update-locale en_US.UTF-8 子句中运行的代码,因此答案需要与该框架一起使用。

1 个答案:

答案 0 :(得分:2)

您可以使用ExpressionVisitor将表达式中的所有Y替换为x.Y并构建新表达式。

class ReplaceParameterExpressionVisitor : ExpressionVisitor
{
    private readonly Expression _target, _replacement;

    public ReplaceParameterExpressionVisitor(ParameterExpression target, Expression replacement)
    {
        _target = target;
        _replacement = replacement;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Equals(_target) ? _replacement : node;
    }
}

访问者非常简单,找到目标ParameterExpression并将其替换为_replacement表达式。

public static class ExpressionExtensions
{
    public static Expression<Func<T, R>> ReplaceParameter<T, R, U>(this Expression<Func<U, R>> origin, Expression<Func<T, U>> accessor)
    {
        var originalParameter = origin.Parameters.Single();
        var replacement = accessor.Body;
        var visitor = new ReplaceParameterExpressionVisitor(originalParameter, replacement);
        var newBody = visitor.Visit(origin.Body);
        return Expression.Lambda<Func<T, R>>(newBody, accessor.Parameters.Single());
    }
}

上面的扩展方法将使用visitor替换body中的参数,获取新的body,并使用new参数构建一个新的lambda表达式。

class User
{
    public string Name { get; set; }
}

Expression<Func<string, bool>> exp = s => s.Equals("Jack");
Expression<Func<User, string>> nameAccessor = u => u.Name;
var newExp = exp.ReplaceParameter(nameAccessor);   // u => u.Name.Equals("Jack")