linqentity-frameworklambdaexpression-trees

How compose Expression: selector + predicate?


Assume that we have two classes

public class EntityA
{
    public EntityB EntityB { get; set; }
}

public class EntityB
{
    public string Name { get; set; }
    public bool IsDeleted { get; set; }
}

And two expressions for selector and predicator

Expression<Func<EntityA, EntityB>> selector = c => c.EntityB;
Expression<Func<EntityB, bool>> predicate = c => c.IsDeleted && c.Name == "AAA";

I need write a method that returns composed expression like a

Expression<Func<TSource, bool>> Compose<TPropType>(Expression<Func<TSource, TPropType>> selector, Expression<Func<TPropType, bool>> predicator)
{
    // Expression API ???
}

In my example result should be

Expression<Func<EntityA, bool>> exp = Compose(selector, predicate);

what is equivalent to

Expression<Func<EntityA, bool>> exp = c => c.EntityB.IsDeleted && c.EntityB.Name == "AAA";

Solution

  • You can try the following:

    static Expression<Func<TSource, bool>> Compose<TSource, TPropType>(
        Expression<Func<TSource, TPropType>> selector,
        Expression<Func<TPropType, bool>> predicator)
    {
        ParameterExpression param = Expression.Parameter(typeof(TSource), "sourceObj");
        Expression invokedSelector = Expression.Invoke(selector, new Expression[] { param });
        Expression invokedPredicate = Expression.Invoke(predicator, new[] { invokedSelector });
    
        return Expression.Lambda<Func<TSource, bool>>(invokedPredicate, new[] { param });
    }
    

    Here's how to use it:

    static void Main()
    {
        Expression<Func<EntityA, EntityB>> selector = c => c.EntityB;
        Expression<Func<EntityB, bool>> predicate = c => c.IsDeleted && c.Name == "AAA";
    
        Expression<Func<EntityA, bool>> exp = Compose(selector, predicate);
        System.Console.WriteLine(exp.Compile()(new EntityA()));
    }