2

我正在查看一个简单的规则引擎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. 如果任何列表项符合条件,我如何让这个函数返回真/假。
  2. 一旦比较了所有列表项(并且没有一个匹配),您如何防止 Expression.Loop 停止循环?

谢谢你的帮助。

4

2 回答 2

1

为什么要使用循环?如果您在 C# 中对检查进行编码,则不会使用循环。你会用Enumerable.Any. 因此生成以下表达式:

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

这被翻译成:

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

这很容易转化为表达式树。

于 2014-03-27T17:37:49.860 回答
0

在您的最后评论之后,听起来您可以使用我为另一个问题建议的方法。替换这部分:

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 和 value

于 2014-03-28T07:24:27.023 回答