36

一言で言えば、C#にはPredicateBuilderと呼ばれる無料のクラスがあり、ここで利用可能なLINQ述語を1つずつ構築します。これは、述語に新しい式を追加するメソッドの抜粋です。誰かがそれを説明できますか?(私はこの質問を見ました、私はそこのような一般的な答えを望んでいません。私は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);
}
4

1 に答える 1

54

あなたが持っているとしましょう:

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)

ご覧のように:

  1. 結果のラムダは、最初の式のパラメーターを再利用します。
  2. 2番目の式のパラメーターの代わりに最初の式のパラメーターを渡すことによって2番目の式を呼び出す本体があります。結果InvocationExpression は、メソッド呼び出し(パラメーターの引数を渡すことによってルーチンを呼び出す)と同等の式のようなものです。
  3. And■最初の式の本体とこれInvocationExpressionを合わせて、結果のラムダの本体を生成します。

LINQプロバイダーは、この操作のセマンティクスを理解し、適切なアクションを実行できる必要があります(たとえば、のようなSQLを生成するWHERE age >= 18 AND gender = 'Male')。

ただし、多くの場合、プロバイダーはInvocationExpression、「ネストされた式-式内の呼び出し」の処理が明らかに複雑になるため、sに問題があります。

これを回避するために、LINQKitはExpandヘルパーも提供します。これは基本的に、呼び出しをネストされた式の本体に置き換え、ネストされた式のパラメーターの使用を適切に置き換えることによって(この場合はに置き換えp2て) 、呼び出し呼び出しをスマートに「インライン化」しますp1。これにより、次のようなものが生成されます。

p1 => p1.Age >= 18 && p1.Gender == "Male"

ラムダで自分で行った場合、これらの述語を手動で組み合わせる方法に注意してください。しかし、LINQKitを使用すると、これらの述語を独立したソースから取得して、簡単に組み合わせることができます。

  1. 「手作業」の式コードを記述せずに。
  2. オプションで、結果のラムダのコンシューマーに対して透過的な方法で。
于 2012-07-15T12:24:10.373 に答える