2014-03-27 51 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和價值