Конструктор выражений для глубокого сравнения свойств

Я смотрел на простой механизм правил http://netmatze.wordpress.com/2012/01/22/building-a-rule-engine-in-c/ и я делаю что-то очень похожее на это. У меня есть два класса, которые выглядят так:

    class A
    {
      public List<B> ListB { get; set; }
    }

    Class B
    {
      public int ID { get; set; }
    }

С моим набором правил, похожим на:

    List<Rule> rules = new List<Rule>{
      new Rule("listB", ExpressionType.Loop, 1, "ID")
    };

Я пытаюсь построить выражение, чтобы в основном взглянуть на свойство класса A listB, зацикливать его, располагая свойство ID каждого элемента, чтобы увидеть, равно ли хотя бы одно из них 1. У меня возникли проблемы с тем, как это сделать. В настоящее время у меня есть что-то вроде (у меня есть жестко закодированные значения в этом, но это в конечном итоге будет изменено, чтобы быть как можно более универсальным). Это выражение не работает, я получаю исключения компиляции:

    var parameterExpression = Expression.Parameter(typeof(A));
    var listB = MemberExpression.Property(parameterExpression, "ListB");
    var leftOperand = MemberExpression.Property(Expression.Parameter(typeof(B)), "ID");
    var rightOperand = Expression.Constant(1); //1
    var found = Expression.Variable(typeof(bool), "found");

    return Expression.Lambda<Func<T, bool>>(
          Expression.Block(
              listB,
              found,
              Expression.Loop( 
                Expression.Block(
                  Expression.IfThen(
                    Expression.Equal(
                      leftOperand,
                      rightOperand
                     ),//equal
                     Expression.Assign(
                       found,
                       Expression.Constant(true)
                     )//set to true
                  )                     
                )//block
              )//loop
            ),
            A
      ).Compile();

В итоге я вызову набор правил для моего объекта следующим образом:

    Engine ruleEngine = new Engine();
    var compiledRules = rules.Select(r => ruleEngine.CompileRule<A>(r)).ToList();
    var result = compiledRules.All(rule => rule(objA));

Мои вопросы:

  1. Как мне заставить эту функцию возвращать true/false, если какой-либо из элементов списка соответствовал условию.
  2. Как предотвратить прерывание цикла Expression.Loop после сравнения всех элементов списка (и ни один из них не сопоставлен)?

Спасибо за любую помощь.

2 ответа

Зачем использовать цикл? Вы не использовали бы цикл, если бы кодировали проверку в C#. Вы бы использовали Enumerable.Any, Так что сгенерируйте следующее выражение:

A a;
return a.ListB.Any(b => b.ID == 1);

Это переводится на:

A a;
return Enumerable.Any(a.ListB, b => b.ID == 1);

Это легко переносится на деревья выражения.

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

var childProperty = parameter.Type.GetProperty(properties[0]);
var left = Expression.Property(parameter, childProperty);
var right = Expression.Constant(test, typeof(int));
navigationPropertyPredicate = Expression.Equal(left, right);
resultExpression = MakeLambda(parameter, navigationPropertyPredicate);

с чем-то, используя ваш ruleOperator и значение

Другие вопросы по тегам