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<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”从范围“”中引用,但未定义
你能告诉我怎么了吗?
非常感谢,
【问题讨论】:
【参考方案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>> 之间:从范围引用的主要内容,如果未能解决你的问题,请参考以下文章
Python 中的 AndAlso (&&) 和 OrElse (||) 逻辑运算符的等价物是啥?