I've tried to implement this using Expression Trees, and got it to get two expressions, but now I didn't get to combine these expressions to build one to pass to the final
First, you need to declare a parameter for your final (outer) lambda. Then you need to invoke your two filter (inner) lambdas independently, passing in the same argument to each:
// using E = System.Linq.Expressions.Expression;
var item = E.Parameter(typeof(TView));
var combined = E.Lambda<Func<TView, bool>>(
E.AndAlso(
E.Invoke(parentCodeFilterExpression, item),
E.Invoke(textFilterExpression, item)),
item);
If you need these expressions to be compatible with a query provider like Entity Framework, things get a bit messier because Invoke
expressions probably aren't supported. You'll have to manually inline the two filter lambdas, which requires walking each filter's body and replacing the inner parameter references with references to the outer lambda's parameter:
// using E = System.Linq.Expressions.Expression;
sealed class ParameterReplacementVisitor : ExpressionVisitor
{
private readonly IDictionary<E, E> _replacements;
public ParameterReplacementVisitor(IDictionary<E, E> replacements)
{
_replacements = replacements;
}
protected override Expression VisitParameter(ParameterExpression node)
{
E replacement;
if (_replacements.TryGetValue(node, out replacement))
return this.Visit(replacement);
return base.VisitParameter(node);
}
}
// ...
var item = E.Parameter(typeof(TView));
var visitor = new ParameterReplacementVisitor(
new Dictionary<E, E> {
{ parentCodeFilterExpression.Parameters[0], item },
{ textFilterExpression.Parameters[0], item }
}
);
var combined = E.Lambda<Func<TView, bool>>(
E.AndAlso(
visitor.Visit(parentCodeFilterExpression.Body),
visitor.Visit(textFilterExpression.Body)),
item);
Alternatively, if you are composing the inner expressions in a closed environment as your post suggests, you could simply pass the outer lambda parameter as an argument to the methods that construct the inner expressions, and return just the bodies (don't bother wrapping the inner filters in lambdas).