使用运行时索引器使用表达式树访问类型的元素

时间:2019-08-30 07:15:27

标签: nrules

我想使用运行时索引器而不是某个固定的零索引值来针对输入数组数据验证规则。 如果我在session.Insert()中一个接一个地插入数据,它会起作用 如果我将sesion.InsertAll()与数组数据一起使用将无法正常工作

我尝试向索引器提供Expression.Constant值,但没有动作触发

class Program
    {
        static void Main(string[] args)
        {
            RuleTestWithSingleInsertData();

           // RuleTestWithInsertDataAll();

            Console.ReadKey();
        }

        public static void RuleTestWithSingleInsertData()
        {
            try
            {
                CustomRuleRepository repository = new CustomRuleRepository();

                List<RuleEngineEntity> rules = new List<RuleEngineEntity>();
                rules.Add(new RuleEngineEntity { FieldName = "Age", Name = "CustomerCheck", Value = 25 });

                repository.LoadRuleForTest1(rules.FirstOrDefault());

                //Compile rules
                var factory = repository.Compile();

                //Create a working session
                var session = factory.CreateSession();

                RuleEngineRequestModel ruleEngineRequestModel = new RuleEngineRequestModel
                {
                    ruleList = rules,
                    customerData = new List<Customer>() { new Customer { Name = "A", Age = 19 },
                    new Customer { Name = "B", Age = 26 } }.ToArray()
                };

                 session.InsertAll(ruleEngineRequestModel.customerData);

                var IspassedorNot = session.Fire(); 
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        public static void RuleTestWithInsertDataAll()
        {
            try
            {
                CustomRuleRepository repository = new CustomRuleRepository();

                List<RuleEngineEntity> rules = new List<RuleEngineEntity>();
                rules.Add(new RuleEngineEntity { FieldName = "Age", Name = "CustomerCheck", Value = 25 });

                repository.LoadRuleForTest2(rules.FirstOrDefault());

                //Compile rules
                var factory = repository.Compile();

                //Create a working session
                var session = factory.CreateSession();

                RuleEngineRequestModel ruleEngineRequestModel = new RuleEngineRequestModel
                {
                    ruleList = rules,
                    customerData = new List<Customer>() { new Customer { Name = "A", Age = 28 },
                    new Customer { Name = "B", Age = 26 } }.ToArray()
                };

                session.InsertAll(ruleEngineRequestModel.customerData);

                var IspassedorNot = session.Fire();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }

    public class RuleEngineRequestModel
    {
        public List<RuleEngineEntity> ruleList { get; set; }

        public Customer[] customerData { get; set; }

        public List<Customer> customerDataList { get; set; }
    }

    public class RuleEngineEntity
    {
        public string Name { get; set; }

        public int Value { get; set; }

        public string Operator { get; set; }

        public string FieldName { get; set; }

        public bool SendEmail { get; set; }

    }

    public class Customer
    {
        public string Name { get; set; }

        public int Age { get; set; }

    }

    public class CustomRuleRepository : IRuleRepository
    {
        private readonly IRuleSet _ruleSet = new RuleSet("customerRule");

        public IEnumerable<IRuleSet> GetRuleSets()
        {
            return new[] { _ruleSet };
        }

        public void LoadRuleForTest1(RuleEngineEntity rule)
        {
            _ruleSet.Add(BuildRuleForTest1(rule));
        }

        public void LoadRuleForTest2(RuleEngineEntity rule)
        {
            _ruleSet.Add(BuildRuleForTest2(rule));
        }

        public List<IRuleDefinition> BuildRuleForTest1(RuleEngineEntity rule)
        {
            return Test1(rule);
        }

        public List<IRuleDefinition> BuildRuleForTest2(RuleEngineEntity rule)
        {
            return Test2(rule);
        }


        public List<IRuleDefinition> Test1(RuleEngineEntity rule)
        {
            RuleBuilder builder = new RuleBuilder();
            builder.Name("DefaultRules");

            try
            {
                var modelPattern = builder.LeftHandSide().Pattern(typeof(Customer), "CustomerCheck");
                var modelParameter = modelPattern.Declaration.ToParameterExpression();

                var expres = Expression.Property(modelParameter, rule.FieldName);

                var binaryExpression = Expression.GreaterThan(expres, Expression.Constant(rule.Value));

                LambdaExpression expressionCondition = Expression.Lambda(binaryExpression,
                        modelParameter);


                modelPattern.Condition(expressionCondition);

                Expression<Action<IContext, Customer, RuleEngineEntity>> action =
                                 (ctx, CustomerCheck, rules) => FireActionAsync(ctx, CustomerCheck, rules);

                builder.RightHandSide().Action(action);
            }

            catch (Exception e)
            {
                // throw new Exception(e.Message);
            }

            var buildRule = builder.Build();

            return new List<IRuleDefinition> { buildRule };
        }

        public List<IRuleDefinition> Test2(RuleEngineEntity rule)
        {
            RuleBuilder builder = new RuleBuilder();
            builder.Name("DefaultRules");

            try
            {                
                   var modelPattern = builder.LeftHandSide().Pattern(typeof(RuleEngineRequestModel), "CustomerCheck");
                var modelParameter = modelPattern.Declaration.ToParameterExpression();
                var customerDataInArray = Expression.Property(modelParameter, nameof(RuleEngineRequestModel.customerData));

                var indx = Expression.Parameter(typeof(int), "index");

                var customerData = Expression.ArrayIndex(customerDataInArray, indx);

                var expres = Expression.Property(customerData, rule.FieldName);

                var binaryExpression = Expression.GreaterThan(expres, Expression.Constant(rule.Value));

                LambdaExpression expressionCondition = Expression.Lambda(binaryExpression,
                        modelParameter);

                modelPattern.Condition(expressionCondition);

                Expression<Action<IContext, Customer>> action =
                                  (ctx, CustomerCheck) => FireActionAsync(ctx, CustomerCheck, null);

                builder.RightHandSide().Action(action);
            }

            catch (Exception e)
            {
                // throw new Exception(e.Message);
            }

            var buildRule = builder.Build();

            return new List<IRuleDefinition> { buildRule };
        }

        public void FireActionAsync(IContext ctx, Customer customer, RuleEngineEntity rule=null)
        {
            Console.WriteLine($"{rule.Name} Triggered");
        }
    }

错误:从作用域”引用了类型为'System.Int32'的变量'index',但未定义

预期:要使用动态索引器针对数组数据验证规则。

1 个答案:

答案 0 :(得分:1)

乍一看,您似乎在将事实插入会话中时传入了一系列客户,但是规则正在寻找RuleEngineRequestModel。

还请注意-为什么将数组初始化为列表,然后转换为数组,而不是仅仅初始化为数组?即

var ruleEngineRequestModel = new RuleEngineRequestModel
{
    ruleList = rules,
    customerData = {
        new Customer { Name = "A", Age = 28 },
        new Customer { Name = "B", Age = 26 }
    }
};

最后,为什么要在插入数据的同时插入规则?看来这会带来更多的麻烦,而不是带来更多的麻烦,尤其是在您的运行时规则构建器完全忽略它们的情况下。

编辑:有机会看到了更新的代码,这证实了我的怀疑-如果您对这两个测试都使用规则1,则它应该可以工作(相反,它将为每个客户触发) 。规则2永远无法工作的原因是因为它期望使用RuleEngineRequestModel,但是您直接传递了IEnumerable。直接传递请求模型并继续使用规则2,或者完全废弃规则2。