Ответ 1
Скажем, у вас есть:
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
вместе, чтобы создать тело полученной лямбда.
Идея заключается в том, что поставщик LINQ должен уметь понимать семантику этой операции и принимать разумный ход действий (например, генерировать SQL, например WHERE age >= 18 AND gender = 'Male'
).
Часто провайдеры имеют проблемы с InvocationExpression
s из-за очевидных осложнений обработки "вложенного выражения-вызова внутри выражения".
Чтобы обойти это, LINQKit также предоставляет помощник Expand
. Это, по сути, "inlines" вызов вызова умно, заменив вызов телом вложенного выражения, соответствующим образом заменив использование вложенных параметров выражения (в этом случае заменив p2
на p1
). Это должно вызвать что-то вроде:
p1 => p1.Age >= 18 && p1.Gender == "Male"
Обратите внимание, что это, как вы бы вручную объединили эти предикаты, если бы вы сделали это самостоятельно в лямбда. Но с LINQKit, вы можете получить эти предикаты из независимых источников и легко объединить их:
- Без написания кода выражения "вручную".
- Необязательно, таким образом, чтобы это было прозрачно для потребителей полученной лямбда.