Сложное дерево выражений без изменения контекста параметра - PullRequest
0 голосов
/ 19 ноября 2018

мне нужно динамически сгенерировать выражение вроде этого:

Expression<Func<MyClass, bool>> expr = x => (x.SomeField.CompareTo(someValue) <= 0);

пытается сделать это так:

var paramExpr = Expression.Parameter(typeof(MyClass), "x");
Expression<Func<MyClass, FieldType>> pathToField = x => x.SomeField;
Expression path = pathToField;
if (!(path is LambdaExpression lambdaMember))
    throw ...;
Expression valueExpr = Expression.Constant(someValue);
var bodyExpr = Expression.LessThanOrEqual(Expression.Call(lambdaMember.Body, "CompareTo", null, valueExpr ), Expression.Constant(0));
return Expression.Lambda<Func<MyClass, FieldType>>(bodyExpr, paramExpr);

но всегда получаю ошибку при попытке скомпилировать это:

переменная 'x' типа 'MyClass', на которую ссылается область действия '', но она не определена

как я мог бы сделать это правильно?

1 Ответ

0 голосов
/ 19 ноября 2018

Проблема здесь в том, что вы используете lambdaMember.Body, который ссылается на x из x => x.SomeField - но поскольку вы только использовали .Body, это не определено - и не связанона x с Expression.Parameter(typeof(MyClass), "x");

В общем случае здесь есть 2 варианта:

  • вызывает всю лямбду (то есть lambdaMember, не lambdaMember.Body) - передача аргументов для использования в качестве параметров
  • перезапись внутренней лямбды во время выполнения с использованием ExpressionVisitor - выгрузка экземпляровx из внутреннего выражения с тем, что вы хотите использовать в качестве аргумента - предположительно paramExpr

Первый вариант проще и просто Expression.Invoke:

var bodyExpr = Expression.LessThanOrEqual(
    Expression.Call(Expression.Invoke(lambdaMember, paramExpr),
    "CompareTo", null, valueExpr), Expression.Constant(0));

Примечание: там - это третий вариант в этом случае, так как это относительно простой пример - вы можете просто перехватить параметр из внутреннего выражения ииспользуйте его вместо , объявив paramExpr в качестве выражения нового параметра:

var paramExpr = lambdaMember.Parameters.Single();
Expression valueExpr = Expression.Constant(someValue);
var bodyExpr = Expression.LessThanOrEqual(
    Expression.Call(lambdaMember.Body,
    "CompareTo", null, valueExpr), Expression.Constant(0));
return Expression.Lambda<Func<MyClass, FieldType>>(bodyExpr, lambdaMember.Parameters);
...