How do I compose Linq Expressions? ie Func>, Exp>, Exp>>

前端 未结 2 542
[愿得一人]
[愿得一人] 2020-12-08 16:22

I\'m creating a Validator class. I\'m attempting to implement the Linq SelectMany extension methods for my validator to be able to compose

2条回答
  •  感情败类
    2020-12-08 17:14

    While dtb's answer works for several scenarios, it is suboptimal as such an expression cannot be used in Entity Framework, as it cannot handle Invoke calls. Unfortunately, to avoid those calls one needs a lot more code, including a new ExpressionVisitor derived class:

    static Expression> Compose(Expression> f,
                                                   Expression> g)
    {
        var ex = ReplaceExpressions(f.Body, f.Parameters[0], g.Body);
    
        return Expression.Lambda>(ex, g.Parameters[0]);
    }
    
    static TExpr ReplaceExpressions(TExpr expression,
                                           Expression orig,
                                           Expression replacement)
        where TExpr : Expression 
    {
        var replacer = new ExpressionReplacer(orig, replacement);
    
        return replacer.VisitAndConvert(expression, nameof(ReplaceExpressions));
    }
    
    private class ExpressionReplacer : ExpressionVisitor
    {
        private readonly Expression From;
        private readonly Expression To;
    
        public ExpressionReplacer(Expression from, Expression to)
        {
            From = from;
            To = to;
        }
    
        public override Expression Visit(Expression node)
        {
            return node == From ? To : base.Visit(node);
        }
    }
    

    This replaces every instance of the first parameter in the first expression with the expression in the second expression. So a call like this:

    Compose((Class1 c) => c.StringProperty, (Class2 c2) => c2.Class1Property

    Would yield the expression (Class2 c2) => c2.Class1Property.StringProperty.

提交回复
热议问题