C# 表达式树-替换表达式

C# 表达式树-替换表达式,c#,expression-trees,C#,Expression Trees,考虑两个表达式树: Expression<Func<float, float, float>> f1 = (x, y) => x + y; Expression<Func<float, float>> f2 = x => x * x; 最简单的方法是使用Expression.Lambda和Expression.Invoke,但结果如下 (x, y) => f1(x, f2(y)) 但这对我来说是不可接受的,因为ORM限制无法正

考虑两个表达式树:

Expression<Func<float, float, float>> f1 = (x, y) => x + y;
Expression<Func<float, float>> f2 = x => x * x;
最简单的方法是使用
Expression.Lambda
Expression.Invoke
,但结果如下

(x, y) => f1(x, f2(y))
但这对我来说是不可接受的,因为ORM限制无法正确处理invoke/lambda


是否可以在不完全遍历表达式树的情况下构造表达式?可以找到满足我需要的工作示例,但我希望得到更简单的解决方案。

如果不完全遍历这两个表达式,就无法完成此操作。幸运的是,
ExpressionVisitor
使完全遍历变得非常简单:

class ReplaceParameter : ExpressionVisitor {
    private readonly Expression replacement;
    private readonly ParameterExpression parameter;
    public ReplaceParameter(
        ParameterExpression parameter
    ,   Expression replacement
    ) {
        this.replacement = replacement;
        this.parameter = parameter;
    }
    protected override Expression VisitParameter(ParameterExpression node) {
        return node == parameter ? replacement : node;
    }
}
使用此访问者两次以完成替换:

Expression<Func<float,float,float>> f1 = (x, y) => x + y;
Expression<Func<float,float>> f2 = x => x * x;
var pX = f2.Parameters[0];
var pY = f1.Parameters[1];
var replacerF2 = new ReplaceParameter(pX, pY);
var replacerF1 = new ReplaceParameter(pY, replacerF2.Visit(f2.Body));
var modifiedF1 = Expression.Lambda(
    replacerF1.Visit(f1.Body)
,   f1.Parameters
);
Console.WriteLine(modifiedF1);

没有表达式树的完全遍历-否。基本上,您需要参数替换器,它是通过
ExpressionVisitor
实现的。
Expression<Func<float,float,float>> f1 = (x, y) => x + y;
Expression<Func<float,float>> f2 = x => x * x;
var pX = f2.Parameters[0];
var pY = f1.Parameters[1];
var replacerF2 = new ReplaceParameter(pX, pY);
var replacerF1 = new ReplaceParameter(pY, replacerF2.Visit(f2.Body));
var modifiedF1 = Expression.Lambda(
    replacerF1.Visit(f1.Body)
,   f1.Parameters
);
Console.WriteLine(modifiedF1);
(x, y) => (x + (y * y))