Nutshell中的C#有一个名为PredicateBuilder的免费类,它可以逐段构造LINQ谓词here。这是该方法的一个摘录,它为谓词添加了一个新表达式。有人可以解释一下吗? (我已经看过this question,我不想要那样的一般性答案。我正在寻找Expression.Invoke和Expression.Lambda如何构建新表达式的具体解释。)
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
答案 0 :(得分:45)
假设你有:
Expression<Func<Person, bool>> isAdult = p1 => p1.Age >= 18;
// I've given the parameter a different name to allow you to differentiate.
Expression<Func<Person, bool>> isMale = p2 => p2.Gender == "Male";
然后将它们与PredicateBuilder
var isAdultMale = isAdult.And(isMale);
PredicateBuilder
生成的是一个如下所示的表达式:
// Invoke has no direct equivalent in C# lambda expressions.
p1 => p1.Age >= 18 && Invoke(p2 => p2.Gender == "Male", p1)
如你所见:
InvocationExpression
有点像方法调用的表达式等价物(通过传入参数的参数来调用例程)。 And
是第一个表达式的主体,这个InvocationExpression
一起生成了生成的lambda的主体。这个想法是LINQ提供者应该能够理解这个操作的语义并采取合理的行动(例如生成像WHERE age >= 18 AND gender = 'Male'
这样的SQL)。
通常情况下,提供程序会遇到InvocationExpression
的问题,因为在表达式中处理'嵌套表达式调用'会有明显的复杂性。
为了解决这个问题,LINQKit还提供了Expand
帮助器。这通过用嵌套表达式的 body 替换调用来巧妙地“内联”调用调用,适当地替换嵌套表达式参数的使用(在这种情况下,用{{替换p2
1}})。这应该产生类似的东西:
p1
请注意,如果您自己在lambda中完成了这些谓词,请如何手动组合这些谓词。但是使用LINQKit,您可以从独立源获取这些谓词并轻松组合它们: