Comprensione del metodo Expression.Invoke ()

c# expression-trees

Domanda

Ho capito i metodi di estensione di PredicateBuilder scritti da Joseph Albahari e ho visto questa Expression.Invoke e onestamente non sono riuscito a capirne il motivo nel seguente metodo:

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);
}

Anche se lui ha spiegato un po ':

Il lavoro interessante si svolge all'interno dei metodi And e Or. Iniziamo invocando la seconda espressione con i parametri della prima espressione. Un'espressione Invoke chiama un'altra espressione lambda usando le espressioni date come argomenti. Possiamo creare l'espressione condizionale dal corpo della prima espressione e dalla versione invocata della seconda. Il passo finale è quello di avvolgere questo in una nuova espressione lambda.

MSDN mi dice che:

Crea un'espressione di chiamata che applica un'espressione delegata o lambda a un elenco di espressioni di argomento.

e questo ha senso per me un po '. Quindi in pratica non devo passare argomenti se uso un'espressione del genere.

Ma per qualche motivo non riuscivo a capirlo. Forse sono stanco o qualcosa del genere.

Domande:

  1. Quando e in quale situazione ha senso usare InvocationExpression .
  2. Qualcuno può spiegare come il metodo Or<T> method (o AndElse<T> ) AndElse<T> poco meglio?

Aggiornare:

Stavo pensando a InvocationExpression quando venivo dal lavoro a casa e questo mi ha fatto pensare in questo modo:

Quando invochiamo un metodo, diciamo semplicemente CallMe(phoneNumber, time); e questo è chiamato invocazione del metodo. Quindi, InvocationExpression dovrebbe essere un'espressione che esprima CallMe(phoneNumber, time); . È simile a LambdaExpression che esprime un lambda come t => t + 2 . Quindi in pratica si tratta di un'invocazione di metodo che viene applicata agli argomenti (non ai parametri). Quindi, come invocazione, non è più necessario avere bisogno di parametri ma forse restituire qualcosa poiché gli argomenti sono già applicati ai suoi parametri.

Per ulteriori informazioni sul codice di cui sto parlando, visitare http://www.albahari.com/nutshell/predicatebuilder.aspx

Risposta accettata

Immagina di non aver lavorato con le espressioni, ma con i delegati. Quindi potresti scrivere Or questo modo:

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

Si crea un nuovo delegato che richiama i due delegati, combinati usando || . Quando lo riscrivi per utilizzare le espressioni, il richiamo di un delegato si trasforma in 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);
}

Il motivo per cui l'effettivo Or non è scritto in questo modo è (molto probabilmente) un'ottimizzazione: non è necessario richiamare entrambe le espressioni, è possibile riutilizzare il corpo e il parametro da uno di essi. (Ma non è possibile riutilizzarli entrambi, perché hanno parametri diversi).



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché