这里有两个问题。首先是如果你使用Expression.And,这相当于二元运算符&,这可能不是你想要的。你必须写
Expression.AndAlso(e1, e2)
得到e1 && e2的等价物。
更大的问题是您试图将两个 lambda 表达式与 && 结合起来,这是不可能的,因为 && 适用于布尔表达式。你想要的是,给定两个 lambda 表达式 lambda1 = x => e1 和 lambda2 = x => e2,返回 x => e1 && e2。
为了实现这一点,请按照以下步骤操作:
- 新建一个
ParameterExpressionp。
- 将
lambda1.Body 中的参数替换为p(您可以使用ExpressionVisitor 执行此操作)以获得renamedBody1。
- 将
lambda2.Body中的参数替换为p得到renamedBody2。
- 现在你可以构造了
Expression.Lambda<Func<Item, bool>>(
Expression.AndAlso(renamedBody1, renamedBody2), p);
这是您可以用作Where 方法的参数的表达式。
注意:如果您确保在使用Expression.Lambda() 构造两个 lambda 表达式时使用相同的参数表达式,则可以避免参数重命名。但是,您不能像在代码中那样使用 => 语法优雅地构造它们,即使它们在两个 lambda 表达式中都被命名为 item,也会产生 不同的 参数。
完整代码
或者,只需在以下代码中使用And 扩展方法(lambda1.And(lambda2)):
/// <summary>
/// Extension methods related to <see cref="Expression" />.
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// Renames all parameter names equal to <paramref name="oldParameterName" /> in
/// <paramref name="expression" /> to <paramref name="newParameter" />.
/// </summary>
[NotNull]
public static Expression ReplaceParameter([NotNull] this Expression expression,
[NotNull] string oldParameterName,
[NotNull] ParameterExpression newParameter)
{
if (expression == null) throw new ArgumentNullException(nameof(expression));
if (oldParameterName == null) throw new ArgumentNullException(nameof(oldParameterName));
if (newParameter == null) throw new ArgumentNullException(nameof(newParameter));
AlphaRenamingExpressionVisitor visitor =
new AlphaRenamingExpressionVisitor(oldParameterName, newParameter);
return visitor.Visit(expression).AsNotNull();
}
/// <summary>
/// Returns the conjunction of the two given predicate expressions, performing alpha renamings if necessary.
/// </summary>
[NotNull]
public static Expression<Func<T, bool>> And<T>([NotNull] this Expression<Func<T, bool>> e1,
[NotNull] Expression<Func<T, bool>> e2)
{
if (e1 == null) throw new ArgumentNullException(nameof(e1));
if (e2 == null) throw new ArgumentNullException(nameof(e2));
return binaryOperation(e1, e2, Expression.AndAlso);
}
/// <summary>
/// Returns the negation of the given predicate expression.
/// </summary>
[NotNull]
public static Expression<Func<T, bool>> Not<T>([NotNull] this Expression<Func<T, bool>> e1)
{
if (e1 == null) throw new ArgumentNullException(nameof(e1));
return Expression.Lambda<Func<T, bool>>(Expression.Not(e1.Body),
e1.Parameters);
}
/// <summary>
/// Returns the disjunction of the two given predicate expressions, performing alpha renamings if necessary.
/// </summary>
[NotNull]
public static Expression<Func<T, bool>> Or<T>([NotNull] this Expression<Func<T, bool>> e1,
[NotNull] Expression<Func<T, bool>> e2)
{
if (e1 == null) throw new ArgumentNullException(nameof(e1));
if (e2 == null) throw new ArgumentNullException(nameof(e2));
return binaryOperation(e1, e2, Expression.OrElse);
}
[NotNull]
private static Expression<Func<T, bool>> binaryOperation<T>([NotNull] Expression<Func<T, bool>> e1,
[NotNull] Expression<Func<T, bool>> e2, [NotNull] Func<Expression, Expression, Expression> binaryOp)
{
if (binaryOp == null) throw new ArgumentNullException(nameof(binaryOp));
if (e1.Parameters[0].Equals(e2.Parameters[0]))
{
return Expression.Lambda<Func<T, bool>>(binaryOp(e1.Body, e2.Body), e1.Parameters[0]);
}
ParameterExpression newParam = Expression.Parameter(typeof(T), "x" + Guid.NewGuid().ToString("N"));
Expression renamedBody1 = e1.Body.ReplaceParameter(e1.Parameters[0].Name, newParam);
Expression renamedBody2 = e2.Body.ReplaceParameter(e2.Parameters[0].Name, newParam);
return Expression.Lambda<Func<T, bool>>(binaryOp(renamedBody1, renamedBody2),
newParam);
}
private class AlphaRenamingExpressionVisitor : ExpressionVisitor
{
[NotNull] private readonly string oldParameterName;
[NotNull] private readonly ParameterExpression newParameter;
/// <summary>
/// Initializes a new instance of <see cref="AlphaRenamingExpressionVisitor" /> with the given parameters.
/// </summary>
public AlphaRenamingExpressionVisitor([NotNull] string oldParameterName,
[NotNull] ParameterExpression newParameter)
{
this.oldParameterName = oldParameterName ?? throw new ArgumentNullException(nameof(oldParameterName));
this.newParameter = newParameter ?? throw new ArgumentNullException(nameof(newParameter));
}
/// <inheritdoc />
[NotNull]
protected override Expression VisitParameter([NotNull] ParameterExpression node)
{
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
return node.Name == oldParameterName ? newParameter : node;
}
}
}