Calling these lambda expressions is something you don't want to do. What you have to do is rewrite the expressions. You just need a way to bind values ββto lambda expressions, as if you were invoking them. To do this, rewrite the bodies of the expressions that replace the parameters with the values ββto which you are bound. You can use this SubstitutionVisitor , to do this:
public class SubstitutionVisitor : ExpressionVisitor { public Expression OldExpr { get; set; } public Expression NewExpr { get; set; } public override Expression Visit(Expression node) { return (node == OldExpr) ? NewExpr : base.Visit(node); } }
Given these expressions, for example:
Expression<Func<EntityA, EntityB>> selector = entityA => entityA.EntityB; Expression<Func<EntityB, bool>> predicate = entityB => entityB.IsDeleted && entityB.Name == "AAA";
The goal is to effectively rewrite it so that it becomes:
Expression<Func<EntityA, bool>> composed = entity => entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA";
static Expression<Func<TSource, bool>> Compose<TSource, TProp>( Expression<Func<TSource, TProp>> selector, Expression<Func<TProp, bool>> predicate) { var parameter = Expression.Parameter(typeof(TSource), "entity"); var property = new SubstitutionVisitor { OldExpr = selector.Parameters.Single(), NewExpr = parameter, }.Visit(selector.Body); var body = new SubstitutionVisitor { OldExpr = predicate.Parameters.Single(), NewExpr = property, }.Visit(predicate.Body); return Expression.Lambda<Func<TSource, bool>>(body, parameter); }
To understand what is happening here, explain in turn:
Create a new parameter for the new lambda that we are creating.
entity => ...
Given the selector, replace all instances of the original entityA parameter entityA our new entity parameter from the lambda body to get the property.
entityA => entityA.EntityB // becomes entity.EntityB
Given the predicate, replace all instances of the original entityB parameter entityB the previously obtained entity.EntityB property from the lambda body to get the body of our new lambda.
entityB => entityB.IsDeleted && entityB.Name == "AAA" // becomes entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA"
Put it all together in a new lambda.
entity => entity.EntityB.IsDeleted && entity.EntityB.Name == "AAA"
source share