2010-03-09 15 views
5

me falta lo obvio: ¿Cómo se accede al valor de un parámetro dentro de un árbol de expresión expresión lambda?obtener el valor de tiempo de ejecución de un ParameterExpression en un árbol de expresión

Escenario: Para un delegado x I crear dinámicamente una expresión lambda con un cuerpo de árbol de expresión que tiene la misma firma que el delegado x. Dentro del cuerpo del lamdba, realizo algunas tareas de validación, comprobación, registro (esto es solo código de prueba, no producción), y luego invoco el delegado x original con los parámetros originales. Si el delegado tiene un valor de retorno, esto también se devuelve.

que funciona bastante bien (incluyendo la aprobación de los parámetros para el delegado original).

Pero estoy golpeando una pared de ladrillos si quiero acceder a los valores de los parámetros originales pasan a la delegado/lambda.

seudo código:

var del = new Func<string, int>(_=> {return 42;}); 
var paramDefs = Array.ConvertAll<ParameterInfo, ParameterExpression>(del.Method.GetParameters(), _ => { return Expression.Parameter(_.ParameterType, _.Name); }); 
var variableTest = Expression.Variable(typeof(string), "str"); 

var expression = Expression.Block(
    new [] { variableTest }, 
    // this line assigns the actual run time value (which is what I need) of the parameter to the variable - but I cannot hardcode the index. 
    //Expression.Assign(variableTest, paramDefs[0]) 
    // this line would assigns the ParameterExpression object (causing a run-time exception since the type of the variable is string) ... I need the _value_ of the first (or nth) parameter. 
    Expression.Assign(variableTest, Expression.ArrayIndex(Expression.Constant(paramDefs), Expression.Constant(0))) 
); 
var lamdba = Expression.Lambda(del.GetType(), expression, "foo", paramDefs); 
var del2 = lamdba.Compile() as Func<string, int>; 
del2("this is a test"); 
+0

Parece que el código comentado es correcto, así que lo haría. Usted dice que no puede codificar el índice. Por qué no? Me parece que eso funcionaría bien. –

+0

Desde entonces he cambiado el código. Inicialmente quise recorrer los paramDefs en el árbol de expresiones (Expression.Loop), visitando cada parámetro uno por uno. Dado que el código funciona en cualquier tipo de delegado, la codificación difícil del índice no habría funcionado. Saqué la construcción de bucle del árbol de expresiones. Para un delegado con 5 parámetros, ahora simplemente genero cinco expresiones (el caso más simple es copiar cada valor de parámetro a un objeto []). Sin embargo, la pregunta inicial todavía me molesta: ¿hay alguna forma de obtener el valor real de una instancia de ParameterExpression? – dalo

Respuesta

3

Parece que el compilador confundido árboles de expresión demasiado (bueno, yo estaba confundido por este código también). Puedo ver lo que trataste de hacer: obtuviste un elemento de una matriz, y luego decidiste recorrer la matriz. Pero no se podía hacer la matriz [ParameterExpression], por lo que se utilizó ArrayIndex. Pero ...

pero ArrayIndex, de hecho, no vuelve "cadena". Devuelve MethodCallExpression. Entonces, en esta expresión "Asignar", en realidad tienes ParameterExpression y MethodCallExpression. El compilador ET es lo suficientemente inteligente como para compilar estas expresiones e intentar asignar resultados. Pero el resultado de su MethodCallExpression es ParameterExpression. Cuando tenía paramDefs [0], tenía ParameterExpression de inmediato y el compilador podía manejar eso. Pero la compilación de expresiones anidadas es más difícil y no está totalmente claro si realmente desea compilar esta expresión anidada o no.

Lo que puede hacer es compilar e invocar el MethodCallExpression usted mismo, por lo que tendrá ParameterExpression en la expresión Assign (como lo hacía antes). Puede parecer así:

// Replace Assign in your Block expression. 
Expression.Assign(variableTest, Expression.Lambda<Func<ParameterExpression>>(Expression.ArrayIndex(Expression.Constant(paramDefs), Expression.Constant(0))).Compile()()), 

Pero podría ser muy pesado en términos de rendimiento (más el código es feo). Entonces, me quedaré con tu idea de sacar el bucle del árbol de expresiones.

Cuestiones relacionadas