Question

Please help to solve issue below:

public class TestParent
{
    public int Number { get; set; }
}

public class Test
{
    public TestParent Parent { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Expression<Func<TestParent, bool>> parentExpression = x => x.Number == 10;
        Expression<Func<Test, TestParent>> testExpression = x => x.Parent;

        var test = new Test {Parent = new TestParent {Number = 10}};

        Expression<Func<Test, bool>> composedExpression = ?; // x => x.Parent.Number == 10

        bool result = composedExpression.Compile()(test);

        if (result)
        {
            Console.WriteLine("Test passed!");
        }
    }
}
Was it helpful?

Solution

We can create a Compose method for expressions like so:

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

This is using the following helper method to replace all instance of one expression with another:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

This allows you to write:

Expression<Func<Test, bool>> composedExpression = 
    testExpression.Compose(parentExpression);

OTHER TIPS

I think you are trying to create a new expression which consist of the logic which is now defined in the two separate expressions parentExpression and testExpression.

Unfortunately you cannot combine expressions like that easily (without breaking down the expressions and using the internal expression-bodies) because the parameters of the expressions are different, and you have to manually create the expression from the contents of the two expressions. You cannot use the two expressions as they are, and combine them.

You can compile the two expressions, and use them in a new expression. It would be something like this. But be warned, the composedExpression will be nothing more than an invoke of the compiled expressions. It will not contain the logic which is now defined in the other two expressions.

Expression<Func<TestParent, bool>> parentExpression = x => x.Number == 10;
Expression<Func<Test, TestParent>> testExpression = x => x.Parent;

var parentExpressionCompiled = parentExpression.Compile();
var testExpressionCompiled = testExpression.Compile();

var test = new Test {Parent = new TestParent {Number = 10}};

Expression<Func<Test, bool>> composedExpression = x => parentExpressionCompiled(testExpressionCompiled(x));

bool result = composedExpression.Compile()(test);

if (result) {
    Console.WriteLine("Test passed!");
}

Get this done:

var composedExpression = testExpression.Combine(parentExpression, true);

where Combine implementation is from: Combining two lambda expressions in c#

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top