【问题标题】:Create an Expression for another with different arguments [duplicate]用不同的参数为另一个创建一个表达式[重复]
【发布时间】:2018-04-08 02:17:40
【问题描述】:

如果X 内部包含Y,是否可以创建一个Expression 接收类型ExpressionExpression 类型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&lt;Func&lt;Y, bool&gt;&gt;

现在,假设我想创建相同的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);
}

PS。这是由实体框架 6 在 .Where 子句中运行的代码,因此答案需要与该框架一起使用。

【问题讨论】:

    标签: c# entity-framework-6 expression


    【解决方案1】:

    您可以使用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,并用新的参数构建一个新的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")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-09
      • 1970-01-01
      • 2021-03-16
      • 2013-08-17
      相关资源
      最近更新 更多