2014-03-27 34 views
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") 
    }; 

我试图建立的表达,主要看类的属性数组listB,循环播放camparing各项目的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 停止循环?

感谢您的帮助。

回答

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

这是容易翻译到表达式树。

+0

肯定我不能用那样的LINQ声明(尽管我很想)的东西。这个代码所在的方法并不了解ListB。它只知道A类和B类的属性名称以及通过通用T传递的A类。 该代码所在的方法如下所示: public Func BuildExpression (string propertyName,ExpressionType ruleOperator,object value,ParameterExpression参数表达式,字符串innerPropertyName) { – riververy

+0

}无论何时您在C#中编写数据库查询,都会隐式创建这样的表达式树。这当然是可能的。请注意,该扩展方法等同于静态方法调用(请参阅编辑)。我明白,没有任何标识符名称是静态的。我只是试图举一个你必须用表达式树建立的结构的例子。大多数C#表达式都可以转换为表达式树。例如,'Enumerable.Any'只是一个'Expression.Call'。这有帮助吗? – usr

0

继您最后的评论,听起来像你可以使用我建议的方法another question。更换这一部分:

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和价值