2016-03-25 15 views
1

ルールエンジン用の式を動的に作成しようとしています。ネストされたタイプとプロパティを許可するまでオペランドとして指定できます。サンプル:Expression.PropertyOrFieldは、文字列プロパティの「System.String」タイプのメンバーではありません。

のExpressionBuilder

public Expression BuildExpression<T>(string propertyName, Enums.Operator ruleOperator, object value, ParameterExpression parameterExpression) 
    { 
     ExpressionType expressionType = new ExpressionType(); 
     Expression body = parameterExpression; 

     foreach (var member in propertyName.Split('.')) 
     { 
      body = MemberExpression.Property(body, member); 
     } 

     var leftOperand = MemberExpression.PropertyOrField(body, propertyName); 
     var rightOperand = Expression.Constant(Convert.ChangeType(value, value.GetType())); 
     FieldInfo fieldInfo = expressionType.GetType().GetField(Enum.GetName(typeof(Enums.Operator), ruleOperator)); 
     var expressionTypeValue = (ExpressionType)fieldInfo.GetValue(ruleOperator); 

     return CastBuildExpression(expressionTypeValue, value, leftOperand, rightOperand); 
    } 

RuleEngine

public Func<T, bool>[] CombineRules<T>(Criterion[] criteria) 
    { 
     List<Func<T, bool>> list = new List<Func<T, bool>>(); 
     foreach (var criterion in criteria) 
     {      
      ExpressionBuilder expressionBuilder = new ExpressionBuilder(); 
      var param = Expression.Parameter(typeof (T)); 
      Expression expression = expressionBuilder.BuildExpression<T>(criterion.PropertyName, 
        criterion.Operator_, criterion.Value, param); 
      Func<T, bool> func = Expression.Lambda<Func<T, bool>>(expression, param).Compile(); 
      list.Add(func); 
     } 

     return list.ToArray(); 
    } 

基準

public class Criterion 
{ 
    private bool propertySet; 
    public string PropertyName { get; set; } 
    public Enums.Operator Operator_ { get; set; } 
    public object Value { get; set; } 

MemberModel

public class MemberModel 
{ 
    public string UserName{ get; set; } 
    public PersonalDetailsModel PersonalDetails {get; set;} 
} 

PersonalDetailsModel

public class PersonalDetailsModel 
{ 
    public int PersonalDetailsId { get; set; } 
    public string Firstname { get; set; } 
    public string Lastname { get; set; } 
    public string Middlename { get; set; } 
    public string DateOfBirth { get; set; } 
    public string GenderType { get; set; } 
    public string SalutationType { get; set; } 
} 

私はruleEngine.CombineRulesに左オペランド、すなわちPropertyName意味= "PersonalDetails.FirstName" として、ネストされたプロパティに渡ししようとすると問題が発生する(基準.ToArray());

「PersonalDetails.Firstname」は明らかにそうであるにもかかわらず、 'System.String'タイプのメンバーではありません。私はしばらくの間これに固執していました。それを引き起こしている可能性はありますか?

ご協力いただければ幸いです。

答えて

2

ここ

Expression body = parameterExpression; 

    foreach (var member in propertyName.Split('.')) 
    { 
     body = MemberExpression.Property(body, member); 
    } 

すでにプロパティパスを処理し、ので、この

var leftOperand = MemberExpression.PropertyOrField(body, propertyName); 

は意味をなさないと例外の発生源です。あなたの例では、bodyにはp.PersonalDetails.FirstName(文字列)のようなものが含まれており、上記の行はp.PersonalDetails.FirstName.PersonalDetails.FirstNameのようなものを作成しようとしています。

代わりにvar leftOperand = body;を使用してください。

あなたはどのような愚かな監督、私のああシンプル

var leftOperand = propertyName.Split('.') 
    .Aggregate((Expression)parameterExpression, Expression.PropertyOrField); 
+0

を使用することにより、全体プロパティパスの処理を短縮することができます。血まみれの金曜日。どうもありがとうございます! – shanomacadaemia

関連する問題