1

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!");
        }
    }
}
1
  • 2
    Please provide more details on what your trying to accomplish. Commented Mar 18, 2014 at 14:01

3 Answers 3

3

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);
Sign up to request clarification or add additional context in comments.

Comments

0

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!");
}

1 Comment

This is essentially useless as a solution in virtually all instances in which Expression objects would be used. Creating an expression out of the compiled expressions is almost certainly not something that anything is going to be able to use.
0

Get this done:

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.