Получение значения во время выполнения ParameterExpression в дереве выражений

Я пропускаю очевидное: Как я получаю доступ к значению параметра в дереве выражений лямбда-выражения?

Сценарий: Для делегата x я динамично создаю лямбда-выражение с телом дерева выражений, которое имеет ту же подпись как делегат x. В теле lamdba я делаю некоторую проверку, проверку, регистрируя материал (это просто тестирует код, не производство), и затем я вызываю исходного делегата x с исходными параметрами. Если у делегата есть возвращаемое значение, это возвращается также.

Это работает вполне хорошо (включая передачу параметров исходному делегату).

Но я врезаюсь в кирпичную стену, если я хочу получить доступ к исходным значениям параметров, переданным делегату/лямбде.

псевдо код:

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");
5
задан dalo 9 March 2010 в 19:00
поделиться

1 ответ

Похоже, вы слишком запутали компилятор деревьев выражений (ну, меня тоже смутил этот код). Я вижу, что вы пытались сделать: вы получили элемент из массива, затем вы решили перебрать этот массив в цикле. Но вы не могли сделать array [ParameterExpression], поэтому вы использовали ArrayIndex. Но ...

Но ArrayIndex фактически не возвращает "строку". Он возвращает MethodCallExpression. Итак, в этом выражении «Назначить» у вас действительно есть ParameterExpression и MethodCallExpression. Компилятор ET достаточно умен, чтобы скомпилировать эти выражения и попытаться присвоить результаты. Но результатом вашего MethodCallExpression является ParameterExpression. Когда у вас был paramDefs [0], у вас сразу было ParameterExpression, и компилятор мог с этим справиться. Но компилировать вложенные выражения сложнее, и совершенно неясно, действительно ли вы хотите скомпилировать это вложенное выражение или нет.

Что вы можете сделать, так это скомпилировать и вызвать MethodCallExpression самостоятельно, чтобы у вас было ParameterExpression в выражении Assign (как и раньше). Это может выглядеть так:

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

Но это может быть очень тяжелый с точки зрения производительности (плюс код уродливый). Итак, я бы придерживался вашей идеи вытащить петлю из дерева выражений.

3
ответ дан 15 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: