Проблема в вашем методе ToExpression
.
leftExpression
и rightExpression
- это каждый LambdaExpression
, и у каждого из них есть свой отдельный T
параметр.
Когда вы создаете LambdaExpression, который вы возвращаете из ToExpression
, вы говорите, что для этого следует использовать параметр из leftExpression
. Но как насчет параметра, который используется в rightExpression
? rightExpression.Body
содержит выражения, использующие rightExpression.Parameters[0]
, и они по-прежнему будут ссылаться на объект rightExpression.Parameters[0]
даже после того, как вы возьмете rightExpression.Body
и поместите его в другое выражение.
Вам нужно переписать rightExpression
использовать тот же параметр, что и leftExpression
. Самый простой способ сделать это - использовать ExpressionVisitor
.
Сначала создайте ExpressionVisitor
, который просто заменяет один параметр другим:
public class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression target;
private readonly ParameterExpression replacement;
public ParameterReplaceVisitor(ParameterExpression target, ParameterExpression replacement) =>
(this.target, this.replacement) = (target, replacement);
protected override Expression VisitParameter(ParameterExpression node) =>
node == target ? replacement : base.VisitParameter(node);
}
Затем используйте это для перезаписи вашего rightExpression.Body
, поэтому он использует тот же объект параметров, что и leftExpression
:
var visitor = new ParameterReplaceVisitor(rightExpression.Parameters[0], leftExpression.Parameters[0]);
var rewrittenRightBody = visitor.Visit(rightExpression.Body.Visit);
var andExpression = Expression.AndAlso(leftExpression.Body, rewrittenRightBody);
return Expression.Lambda<Func<T, bool>>(
andExpression, leftExpression.Parameters[0]);