AndAlso 在几个 Expression<Func<T, bool>> 之间:从范围引用

Posted

技术标签:

【中文标题】AndAlso 在几个 Expression<Func<T, bool>> 之间:从范围引用【英文标题】:AndAlso between several Expression<Func<T, bool>> : referenced from scope 【发布时间】:2012-12-07 16:46:15 【问题描述】:

我有 3 个谓词,我想在它们之间创建一个 AndAlso。我在板上找到了几个示例,但无法解决我的问题。

这些谓词是:Expression&lt;Func&lt;T, bool&gt;&gt;

我有这个代码:

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”从范围“”中引用,但未定义

你能告诉我怎么了吗?

非常感谢,

【问题讨论】:

【参考方案1】:

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

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

问题现在应该很明显了。

Marc Gravell 在 this answer 中建议使用一般的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);

(Marc 的代码,不是我)

【讨论】:

我看到了 Marc 的代码,但没有工作不记得为什么。但我现在再次尝试 试一试,如果它不起作用,请告诉我——它对我有用(你只需要确保它可以被你的代码访问,即公共或内部;我会在我的答案) 是的,这很有效。不知道我在之前的测试中做了什么。但老实说,我不太清楚这一切是如何工作的:) 好吧,你组合了两个表达式,每个表达式都有自己独立的参数。如果您只创建一个新参数,则新形成的表达式不知道如何将其传递给它的子表达式(因为可能有更多参数,每个表达式可以有不同数量的参数等)。 Marc 的解决方案确保参数相同(例如,当您将表达式与其自身组合时),如果它们不同,它将参数从 expr1 传递给 expr2,因此当您调用新表达式时,确切的将相同的参数提供给两个子表达式。 再问一个问题。我创建了一个方法,它接收一个谓词列表,我将所有这些谓词与 AndAlso 扩展方法结合起来。如果 finalPredicate 为空,我该如何管理。我必须创建 2 个查询,一个在 finalPredicate 为 null 时,一个在 finalPredicate 不为 null 时?谢谢,

以上是关于AndAlso 在几个 Expression<Func<T, bool>> 之间:从范围引用的主要内容,如果未能解决你的问题,请参考以下文章

循环在几个输入后结束 C++

在几个可变 lambda 中更改相同的向量

Python 中的 AndAlso (&&) 和 OrElse (||) 逻辑运算符的等价物是啥?

(OrElse and Or) and (AndAlso and And) - 啥时候使用?

相当于SQL中的VB AndAlso?

VB.NET入门 ANDALSO 和OrElse 之于 AND,OR