Consider two expression trees:
Expression<Func<float, float, float>> f1 = (x, y) => x + y;
Expression<Func<float, float>> f2 = x => x * x;
I want to substitute the expression f2
as a second parameter of f1
and obtain the following expression:
Expression<Func<float, float, float>> f3 = (x, y) => x + y * y;
The simplest way is to use Expression.Lambda
and Expression.Invoke
, but the result will look like
(x, y) => f1(x, f2(y))
But this is unacceptable for me due to ORM limitations that cannot handle invoke/lambda properly.
Is it possible to construct the expression without full traversal of expression trees? A working example that fulfill my needs can be found here but I want simpler solution.
You cannot do it without full traversal of both expressions. Fortunately, ExpressionVisitor
makes full traversal really easy:
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;
}
}
Use this visitor twice to complete the replacement:
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);
The above prints
(x, y) => (x + (y * y))