Как получить выражение из лямбда-выражения - PullRequest
0 голосов
/ 11 марта 2020

Я разрабатываю механизм правил, в котором правила устанавливаются в базе данных с таким дизайном:

"PropertyName", "Operator", "PropertyValue" (например, для data.employee.salary = 10000). Это выполняется для основного класса, который имеет данные в качестве свойства, которое фактически указывает на вложенный класс с именем Data, а внутренний класс «data», в свою очередь, имеет свойство employee, которое отображается на внутренний класс Employee со свойством зарплата которая строка прямо сейчас.

Это часть кода RulesEngine, который я кодировал и использует ExpressionTrees:

    // Loop through each of the rules per Ruleset and compile them against the properties of the supplied T object.
            //NOTE: The values in the database column 'PropertyName' should match exactly with the properties of the T class. ​
            rules.ForEach(rule =>​
            {​
                var genericType = Expression.Parameter(typeof(T));​
              //  var key = MemberExpression.Property(genericType, rule.PropertyName);​
                var key = CreateExpression(typeof(T), rule.PropertyName);​ //rule.PropertyName== 'data.employee.salary' 
                var propertyType = GetProp(typeof(T), rule.PropertyName).PropertyType;      // System.String          ​
                ​
                var value = Expression.Constant(Convert.ChangeType(rule.PropertyValue, propertyType));​ //"10000"
​`               if (rule.Operator != ExpressionType.Lambda && rule.Operator != ExpressionType.Default) //This covers both '=' and '<>' or anything Binary-ish Operators setup in the Rules table.​
                {​
                    var binaryExpression = Expression.MakeBinary(rule.Operator, key, value);​
                    compiledExpTreeRules.Add(Expression.Lambda<Func<T, bool>>(key, genericType).Compile());​
                }​

            static LambdaExpression CreateExpression(Type type, string propertyName)
            {​
                    var param = Expression.Parameter(type, "x");​
                    Expression body = param;​
                    foreach (var member in propertyName.Split('.'))​
                    {​
                        body = Expression.PropertyOrField(body, member);​
                    }​
                    return Expression.Lambda(body, param);​
            //return MemberExpression.Property(body, propertyName);​
        }

Проблема, с которой я столкнулся, заключается в том, что я возвращаю Expression.Lambda из моего метода CreateExpression (). Мне пришлось написать этот метод, потому что мой входной класс T имеет вложенные классы внутри и, следовательно, свойства и правила могут быть настроены в базе данных, на уровне свойств листа внутреннего вложенного класса.

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

var binaryExpression = Expression.MakeBinary(rule.Operator, key, value);

Как создать двоичное выражение, когда я уже знаю лямбда-выражение, которое является параметром 'key'? Этот ключ в списке параметров MakeBinary не работает. Я также попробовал key.body, но я просто не знаю, как это сделать: 1) заставить CreateExpression () вернуть MemberExpression.Property или 2) когда он возвращает лямбда-выражение типа x => x.innnerclass1.prop1, как я могу это сделать? использовать это как «ключ» и сделать BinaryExpression? У меня есть лямбда, у меня есть оператор (исходя из БД), и у меня есть значение, но я изо всех сил пытаюсь построить из него двоичное выражение.

Заранее спасибо!

1 Ответ

2 голосов
/ 11 марта 2020

Вопрос немного сбивает с толку, но, похоже, у вас под рукой три вещи:

  • Лямбда-выражение lambda с параметром x и телом x.i.p.
  • Выражение value
  • Вид бинарного оператора - давайте предположим, что это «сложение».

И вы хотите построить лямбду для x => x.i.p + value, это правильно?

Для этого вы бы сказали:

// Given values:
LambdaExpression lambda = whatever;
Expression value = whatever;    
ExpressionType operator = whatever;
// Computed values:
Expression key = lambda.Body;
List<ParameterExpression> ps = lambda.Parameters;
BinaryExpression binop = Expression.MakeBinary(operator, key, value);
LambdaExpression newLambda = Expression.Lambda(binop, ps);

Имеет ли это смысл?

...