web-dev-qa-db-ja.com

Expression.Invoke()メソッドを理解する

私はJosephAlbahariによって書かれたPredicateBuilder拡張メソッドを理解してきましたが、これは_Expression.Invoke_でしたが、正直なところ、次のメソッドではその理由を理解できませんでした。

_public static Expression<Func<T, bool>> Or<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.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
_

彼はそれを少し説明しましたが:

興味深い作業は、AndメソッドとOrメソッドの内部で行われます。まず、最初の式のパラメータを使用して2番目の式を呼び出します。 Invoke式は、指定された式を引数として使用して、別のラムダ式を呼び出します。最初の式の本体と2番目の式の呼び出されたバージョンから条件式を作成できます。最後のステップは、これを新しいラムダ式でラップすることです。

[〜#〜] msdn [〜#〜] は次のことを教えてくれます:

デリゲート式またはラムダ式を引数式のリストに適用するInvocationExpressionを作成します。

これは私には少し意味があります。したがって、基本的に、そのような式を使用する場合は、引数を渡す必要はありません。

でもどういうわけかよくわからなかった。多分私は疲れているか何かです。

質問:

  1. いつ、どのような状況でInvocationExpressionを使用するのが理にかなっています。
  2. _Or<T>_メソッド(または_AndElse<T>_)メソッドがどのように機能するかを誰かが説明できますか?

更新:

仕事から家に帰るときにInvocationExpressionについて考えていたところ、次のように頭に浮かびました。

メソッドを呼び出すときは、単純にCallMe(phoneNumber, time);と言います。これは、メソッド呼び出しと呼ばれます。その場合、InvocationExpressionCallMe(phoneNumber, time);を表す式である必要があります。これは、_t => t + 2_などのラムダを表すLambdaExpressionに似ています。したがって、基本的には、(パラメーターではなく)引数に適用されるメソッド呼び出しです。したがって、呼び出しとして、パラメーターは必要なくなりますが、引数が既にパラメーターに適用されているため、おそらく何かを返します。

私が話しているコードの詳細については、 http://www.albahari.com/nutshell/predicatebuilder.aspx にアクセスしてください。

23
Tarik

エクスプレッションではなく、デリゲートを使用していると想像してください。次に、次のようにOrと書くことができます。

_public static Func<T, bool> Or<T>(this Func<T, bool> expr1, Func<T, bool> expr2)
{
    return x => expr1(x) || expr2(x);
}
_

_||_を使用して組み合わせて、2つのデリゲートを呼び出す新しいデリゲートを作成します。式を使用するようにこれを書き直すと、デリゲートを呼び出すとExpression.Invoke()になります。

_public static Expression<Func<T, bool>> Or<T>(
    this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
    var parameter = Expression.Parameter(typeof(T), "x");
    var invokedExpr1 = Expression.Invoke(expr1, parameter);
    var invokedExpr2 = Expression.Invoke(expr2, parameter);

    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse(invokedExpr1, invokedExpr2), parameter);
}
_

実際のOrがこのように記述されていない理由は、(ほとんどの場合)最適化です。両方の式を呼び出す必要はなく、どちらか一方の本体とパラメーターを再利用できます。 (ただし、パラメーターが異なるため、両方を再利用することはできません。)

37
svick