/// <summary> /// Parse the expression tree /// </summary> /// <typeparam name="T"></typeparam> /// <param name="condition"></param> /// <param name="parm"></param> /// <returns></returns> private static Expression ParseTree <T>( ConditionRuleSet condition, ParameterExpression parm) { IEnumerable <ConditionRuleSet> rules = condition.Rules; Binder binder = condition.Separator == ConditionRuleSeparator.Or ? (Binder)Expression.Or : Expression.And; Expression bind(Expression lef, Expression right) => lef == null ? right : binder(lef, right); Expression left = null; // If multiple rules inner if (condition.Rules != null && condition.Rules.Any()) { foreach (var rule in condition.Rules) { left = bind(left, CreateRuleExpression <T>(rule, parm)); } } else { left = bind(left, CreateRuleExpression <T>(condition, parm)); } return(left); }
private static Expression GetExpression(ConditionRuleSet rule, ParameterExpression param, string field, object value) { MemberExpression property = null; foreach (var member in field.Split('.')) { if (property == null) { property = Expression.Property(param, member); } else { property = Expression.Property(property, member); } } return(CreateOperationExpression(property, rule.Operator, value)); }
private static MethodCallExpression HandleTableRule(ConditionRuleSet rule, string field, object value, MemberExpression property) { // Get the type of T in the IEnumerable<T> or ICollection<T> list var childType = property.Type.GetGenericArguments().First(); // Set it as the param of the any expression var param = Expression.Parameter(childType); var anyExpression = Expression.Lambda(GetExpression(rule, param, field, value), param); var anyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2); anyMethod = anyMethod.MakeGenericMethod(childType); var predicate = Expression.Call(anyMethod, property, anyExpression); return(predicate); }
/// <summary> /// Transform the ConditionRuleSet object to an expression function /// that can be evaluated in LinqToSql queries or whatever /// </summary> /// <typeparam name="T"></typeparam> /// <param name="rules"></param> /// <returns></returns> public static Expression <Func <T, bool> > ParseExpression <T>(ConditionRuleSet rules) { var itemExpression = Expression.Parameter(typeof(T)); var conditions = ParseTree <T>(rules, itemExpression); // If no conditions parsed // Let's return a true predicate if (conditions == null) { return((m) => true); } if (conditions.CanReduce) { conditions = conditions.ReduceAndCheck(); } Console.WriteLine(conditions.ToString()); var query = Expression.Lambda <Func <T, bool> >(conditions, itemExpression); return(query); }
private static ValidateExpressionResult ValidateExpressionRecursive(ConditionRuleSet rule, IEnumerable <string> fieldWhiteList) { if (!string.IsNullOrEmpty(rule.Field) && !fieldWhiteList.Contains(rule.Field)) { return(new ValidateExpressionResult() { InvalidField = rule.Field }); } if (rule.Rules != null) { foreach (var subRule in rule.Rules) { var evaluate = ValidateExpressionRecursive(subRule, fieldWhiteList); if (!evaluate.Success) { return(evaluate); } } } return(ValidateExpressionResult.Valid); }
private static Expression CreateRuleExpression <T>(ConditionRuleSet rule, ParameterExpression parm) { Expression right = null; if (rule.Separator.HasValue && rule.Rules != null && rule.Rules.Any()) { right = ParseTree <T>(rule, parm); return(right); } // If the field is empty, then return true if (string.IsNullOrEmpty(rule.Field)) { return(right); } MemberExpression property = null; try { string field = rule.Field; var fields = field.Split('.'); int i = 0; foreach (var member in fields) { i = i + member.Length + 1; if (property == null) { property = Expression.Property(parm, member); } else { property = Expression.Property(property, member); } if (property.Type.IsArray()) { string subField = ""; try { subField = field.Substring(i, field.Length - i); if (string.IsNullOrEmpty(subField)) { throw new Exception(""); } } catch { throw new JsonRuleEngineException(JsonRuleEngineExceptionCategory.InvalidField, $"The array {field} does not have a subfield. e.g. {field}.Id"); } right = HandleTableRule(rule, subField, rule.Value, property); return(right); } } } catch (Exception e) { throw new JsonRuleEngineException(JsonRuleEngineExceptionCategory.InvalidField, $"The provided field is invalid {rule.Field} : {e.Message} "); } return(CreateOperationExpression(property, rule.Operator, rule.Value)); }
/// <summary> /// Test the conditions /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj">The object to test</param> /// <param name="rules">The conditionRuleSet object</param> /// <returns>True if the conditions are matched</returns> public static bool Evaluate <T>(T obj, ConditionRuleSet rules) { var query = ParseExpression <T>(rules); return(query.Compile().Invoke(obj)); }