简体   繁体   English

用于深度属性比较的表达式生成器

[英]Expression builder for deep property comparison

I was looking at a simple rule engine http://netmatze.wordpress.com/2012/01/22/building-a-rule-engine-in-c/ and I'm doing something very similar to this. 我正在看一个简单的规则引擎http://netmatze.wordpress.com/2012/01/22/building-a-rule-engine-in-c/,并且我正在做与此非常相似的事情。 I have two classes that look like: 我有两个看起来像的类:

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

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

With my rule set looking like: 我的规则集如下所示:

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

I'm trying to build the expression to basically look at class A property listB, loop it camparing each item's ID property to see if at least one equals 1. I'm having trouble on how to do this. 我正在尝试构建一个表达式,以便基本上查看类A的属性listB,将其循环显示每个项目的ID属性,以查看至少一个等于1。我在执行此操作时遇到了麻烦。 I currently have something like (I have hard coded values set in this, but it will eventually be changed to be generic as much as possible). 我目前有类似的东西(我在其中设置了硬编码值,但最终将尽可能多地更改为通用)。 This expression does not work, I get compile exceptions: 此表达式不起作用,我得到了编译异常:

    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();

I'll end up calling the rule set against my object like so: 我最终将针对我的对象调用规则集,如下所示:

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

My questions are: 我的问题是:

  1. How do I get this function to return true/false if any of the list items matched the condition. 如果任何列表项符合条件,如何获取此函数以返回true / false。
  2. How do you prevent the Expression.Loop to stop looping once all list items are compared (and none of them matched)? 一旦比较了所有列表项(没有一个匹配),如何防止Expression.Loop停止循环?

Thanks for any help. 谢谢你的帮助。

Why use a loop? 为什么要使用循环? You wouldn't use a loop if you were coding the check in C#. 如果您使用C#编写检查代码,则不会使用循环。 You'd use Enumerable.Any . 您将使用Enumerable.Any So generate the following expression: 因此,生成以下表达式:

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

This is translated to: 这被翻译为:

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

This is easily translatable to expression trees. 这很容易翻译成表达式树。

Following your last comment it sounds like you could use the approach i suggested for another question . 在您发表最后一条评论之后,听起来您可以使用我为其他问题建议的方法。 Replace this part: 替换此部分:

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);

with something using your ruleOperator and value 使用您的ruleOperator和值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM