Using a LINQ ExpressionVisitor to replace primitive parameters with property references in a lambda expression

后端 未结 2 909
春和景丽
春和景丽 2020-12-24 15:20

I\'m in the process of writing a data layer for a part of our system which logs information about automated jobs that run every day - name of the job, how long it ran, what

2条回答
  •  萌比男神i
    2020-12-24 16:14

    The accepted answer is 'hardcoded' to some specific types. Here's a more general expression rewriter than can substitute a parameter for any other expression (lambda, constant, ...). In the case of a lambda expression the expression's signature needs to change to incorporate the parameters needed by the substituted value.

    public class ExpressionParameterSubstitute : System.Linq.Expressions.ExpressionVisitor
    {
        private readonly ParameterExpression from;
        private readonly Expression to;
        public ExpressionParameterSubstitute(ParameterExpression from, Expression to)
        {
            this.from = from;
            this.to = to;
        }
    
        protected override Expression VisitLambda(Expression node)
        {
            if (node.Parameters.All(p => p != this.from))
                return node;
    
            // We need to replace the `from` parameter, but in its place we need the `to` parameter(s)
            // e.g. F subst F => F
            // e.g. F subst F => F
    
            var toLambda = to as LambdaExpression;
            var substituteParameters = toLambda?.Parameters ?? Enumerable.Empty();
    
            ReadOnlyCollection substitutedParameters
                = new ReadOnlyCollection(node.Parameters
                    .SelectMany(p => p == this.from ? substituteParameters : Enumerable.Repeat(p, 1) )
                    .ToList());
    
            var updatedBody = this.Visit(node.Body);        // which will convert parameters to 'to'
            return Expression.Lambda(updatedBody, substitutedParameters);
        }
    
        protected override Expression VisitParameter(ParameterExpression node)
        {
            var toLambda = to as LambdaExpression;
            if (node == from) return toLambda?.Body ?? to;
            return base.VisitParameter(node);
        }
    }
    

提交回复
热议问题