Reputation: 578
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!");
}
}
}
Upvotes: 1
Views: 1654
Reputation: 203812
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);
Upvotes: 3
Reputation: 578
Get this done:
var composedExpression = testExpression.Combine(parentExpression, true);
where Combine implementation is from: Combining two lambda expressions in c#
Upvotes: 0
Reputation: 22945
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!");
}
Upvotes: 0