簡単に言えば、C#にはPredicateBuilderと呼ばれる無料のクラスがあり、LINQ述語を1つずつ構築します here 。新しい式を述語に追加するメソッドの抜粋を次に示します。誰か説明してもらえますか? (私は この質問 を見ましたが、そのような一般的な答えは望みません。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);
}
あなたが持っているとしましょう:
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
sは最初の式の本体とこのInvocationExpression
を合わせて、結果のラムダの本体を生成します。考え方は、LINQプロバイダーがこの操作のセマンティクスを理解し、賢明なアクションコースを実行できる必要があるということです(たとえば、WHERE age >= 18 AND gender = 'Male'
)。
しかし、多くの場合、プロバイダーはInvocationExpression
sに問題があります。これは、「式内のネストされた式呼び出し」の処理の明らかな複雑さのためです。
これを回避するために、LINQKitはExpand
ヘルパーも提供します。これは、呼び出しをネストされた式のbodyに置き換え、ネストされた式のパラメーターの使用を適切に置き換えて(この場合、p2
with p1
)。これにより、次のようになります。
p1 => p1.Age >= 18 && p1.Gender == "Male"
ラムダで自分で行った場合、これらの述語を手動で結合する方法に注意してください。しかし、LINQKitを使用すると、これらの述語独立したソースからを取得して、簡単に結合できます。