create c# expression-trees

c# - create - Entendiendo el método Expression.Invoke()



lambda c# (1)

He estado entendiendo los métodos de extensión PredicateBuilder escritos por Joseph Albahari y vi esta Expression.Invoke Invocando y honestamente no pude entender la razón de ello en el siguiente método:

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

A pesar de que lo explicó un poco:

El trabajo interesante tiene lugar dentro de los métodos de Y y O. Comenzamos invocando la segunda expresión con los parámetros de la primera expresión. Una expresión de invocación llama a otra expresión lambda utilizando las expresiones dadas como argumentos. Podemos crear la expresión condicional a partir del cuerpo de la primera expresión y la versión invocada de la segunda. El último paso es envolver esto en una nueva expresión lambda.

MSDN me dice que:

Crea una expresión de invocación que aplica una expresión delegada o lambda a una lista de expresiones de argumentos.

Y esto tiene poco sentido para mí. Básicamente, no tengo que pasar ningún argumento si uso la expresión de esa manera.

Pero por alguna razón no podía entenderlo. Tal vez estoy cansado o algo así.

Preguntas:

  1. ¿Cuándo y en qué situación tiene sentido usar InvocationExpression ?
  2. ¿Alguien puede explicar cómo el método Or<T> (o AndElse<T> ) funciona un poco mejor?

Actualizar:

Estaba pensando en InvocationExpression cuando venía del trabajo a mi casa y me dio a entender en mi mente lo siguiente:

Cuando invocamos un método, simplemente decimos CallMe(phoneNumber, time); y esto se llama invocación de método. Entonces, InvocationExpression debe ser una expresión que exprese CallMe(phoneNumber, time); . Es similar a LambdaExpression que expresa un lambda como t => t + 2 . Así que básicamente es una invocación de método que se aplica a argumentos (no a parámetros). Por lo tanto, como invocación, ya no se espera que necesite un parámetro, sino que quizás devuelva algo, ya que los argumentos ya se aplican a sus parámetros.

Para obtener más información sobre el código del que estoy hablando, visite http://www.albahari.com/nutshell/predicatebuilder.aspx


Imagina que no estabas trabajando con expresiones, sino con delegados. Entonces podrías escribir Or así:

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

Crea un nuevo delegado que invoca a los dos delegados, combinados utilizando || . Cuando reescribes esto para usar expresiones, invocar a un delegado se convierte en 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); }

La razón por la que el Or real no está escrito de esta manera es (lo más probable) una optimización: no tiene que invocar ambas expresiones, puede reutilizar el cuerpo y el parámetro de una de ellas. (Pero no puedes reutilizarlos a ambos, porque tienen parámetros diferentes).