8

我有 3 个谓词,我想在AndAlso两者之间做一个。我在板上找到了几个样本,但无法解决我的问题。

这些谓词是:Expression<Func<T, bool>>

我有这个代码:

Expression<Func<T, bool>> predicate1 = ......;
Expression<Func<T, bool>> predicate2 = ......;
Expression<Func<T, bool>> predicate3 = ......;

我创建了一个扩展方法来制作“AndAlso”:

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr, 
    Expression<Func<T, bool>> exprAdd)
{
    var param = Expression.Parameter(typeof(T), "p");
    var predicateBody = Expression.AndAlso(expr.Body, exprAdd.Body);
    return Expression.Lambda<Func<T, bool>>(predicateBody, param);

    //Tried this too
    //var body = Expression.AndAlso(expr.Body, exprAdd.Body);
    //return Expression.Lambda<Func<T, bool>>(body, expr.Parameters[0]);
}

我这样使用:

var finalPredicate = predicate1
    .AndAlso<MyClass>(predicate2)
    .AndAlso<MyClass>(predicate3);

谓词看起来像这样: 在此处输入图像描述

当我在查询中使用时:

var res =  myListAsQueryable().Where(finalPredicate).ToList<MyClass>();

我收到此错误: 从范围“”引用的“BuilderPredicate.MyClass”类型的变量“p”,但未定义

你能告诉我有什么问题吗?

非常感谢,

4

1 回答 1

14

问题是创建一个新参数 - 你可以这样做,但如果你只是将它分配给最终的 lambda,那么你的参数和提供的表达式中的原始参数之间没有任何联系。尝试更改表达式的参数名称,然后检查finalPredicate. 你会看到类似的东西:

{p => (((x.Age == 42) AndAlso (y.Salary == 50)) AndAlso z.FirstName.StartsWith("foo"))}

现在问题应该很明显了。

Marc Gravell 在这个答案中建议一个 general Expression.AndAlso,这正是你所需要的:

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    // need to detect whether they use the same
    // parameter instance; if not, they need fixing
    ParameterExpression param = expr1.Parameters[0];
    if (ReferenceEquals(param, expr2.Parameters[0]))
    {
        // simple version
        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(expr1.Body, expr2.Body), param);
    }
    // otherwise, keep expr1 "as is" and invoke expr2
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(
            expr1.Body,
            Expression.Invoke(expr2, param)), param);
}

(马克的代码,不是我)

于 2012-12-20T08:42:09.330 回答