Árboles de expresión e invocación de un delegado

.net c# delegates expression-trees lambda

Pregunta

Así que tengo un delegate que apunta a una función que no conozco realmente cuando creo por primera vez el objeto delegate . El objeto se establece en alguna función más tarde.

También quiero hacer un árbol de expresiones que invoque al delegado con un argumento (para esta pregunta, el argumento puede ser 5 ). Esta es la parte con la que estoy luchando; El siguiente código muestra lo que quiero pero no compila.

Func<int, int> func = null;
Expression expr = Expression.Invoke(func, Expression.Constant(5));

Para este ejemplo que podría hacer (esto es práctico ya que necesito construir los árboles de expresión en tiempo de ejecución):

Func<int, int> func = null;
Expression<Func<int>> expr = () => func(5);

Esto hace que expr convierta en:

() => Invoke(value(Test.Program+<>c__DisplayClass0).func, 5)

Lo que parece significar que para usar la func delegate , necesito producir el value(Test.Program+<>c__DisplayClass0).func bit.

Entonces, ¿cómo puedo hacer un árbol de expresiones que invoque a un delegado?

Respuesta aceptada

OK, esto muestra cómo se puede hacer (pero en mi opinión es muy poco elegante):

Func<int, int> func = null;
Expression<Func<int, int>> bind = (x) => func(x);

Expression expr = Expression.Invoke(bind, Expression.Constant(5));

Expression<Func<int>> lambda = Expression.Lambda<Func<int>>(expr);
Func<int> compiled = lambda.Compile();

Console.WriteLine(expr);

func = x => 3 * x;
Console.WriteLine(compiled());

func = x => 7 * x;
Console.WriteLine(compiled());

Console.Read();

Esencialmente uso (x) => func(x); para hacer una función que llame a lo que apunta el delegado. Pero puedes ver que expr es demasiado complicado. Por esta razón, no considero que esta respuesta sea buena, pero ¿tal vez se pueda desarrollar?


Respuesta popular

Creo que lo que quieres hacer es usar las propiedades de Destino y Método del delegado para pasar y crear una expresión de llamada. Sobre la base de la muestra de JulianR, este es el aspecto que tendría:

Action<int> func = i => Console.WriteLine(i * i);

var callExpr = Expression.Call(Expression.Constant(func.Target), func.Method, Expression.Constant(5));

var lambdaExpr = Expression.Lambda<Action>(callExpr);
var fn = lambdaExpr.Compile();
fn();    //  Prints 25


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow