如何创建动态NRules

问题描述 投票:0回答:1

我得到这个例外:

variable 'e' of type 'MyClass' referenced from scope '', but it is not defined

我想用嵌套属性创建动态规则。当我创建静态规则时它工作正常,但不是动态模式。另外,如果可能的话,我想使用这些代码行将表达式用于动态规则:

PatternBuilder customerPattern = builder.LeftHandSide().Pattern(typeof(Customer), "customer");
Expression<Func<Customer, bool>> customerCondition = customer => customer.Name == "John Do";
customerPattern.Condition(customerCondition);

我尝试了下面的代码动态创建和执行规则,但我得到一个例外。为什么?

class Program
{
    static void Main(string[] args)
    {
        try
        {
            CustomRuleRepository repository = new CustomRuleRepository();

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

            repository.LoadRules(rules);

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

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

            RuleEngineRequestModel ruleEngineRequestModel = new RuleEngineRequestModel { ruleList = rules, customerData = new Customer { Name = "A", Age = 24 } };

            session.Insert(ruleEngineRequestModel);

            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 class RuleEngineEntity
{
    public string Name { get; set; }
    public int Value { get; set; }
    public string Operator { get; set; }
    public string FieldName { 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 LoadRules(List<RuleEngineEntity> list)
    {
        _ruleSet.Add(
            BuildRule(list)
        );
    }

    public List<IRuleDefinition> BuildRule(List<RuleEngineEntity> list)
    {
        NRules.RuleModel.Builders.RuleBuilder builder = null;
        List<IRuleDefinition> rulesList = new List<IRuleDefinition>();
        builder = new NRules.RuleModel.Builders.RuleBuilder();
        builder.Name("CustomerDetail");
        ParameterExpression customerParameter = null;
        LambdaExpression customerCondition = null;
        PatternBuilder customerPattern = null;
        try
        {
            var orGroup = builder.LeftHandSide().Group(GroupType.Or);

            foreach (var item in list)
            {
                var andGroup = orGroup.Group(GroupType.And);

                customerPattern = andGroup.Pattern(typeof(RuleEngineRequestModel), item.Name);
                customerParameter = customerPattern.Declaration.ToParameterExpression();

                customerCondition =
                    Expression.Lambda(
                        Expression.GreaterThan(CreateParameterExpression(typeof(RuleEngineRequestModel), "customerData", typeof(Customer), item.FieldName),
                            Expression.Constant(item.Value)), customerParameter);
                customerPattern.Condition(customerCondition);
            }

            Expression<Action<IContext>> action =
                (ctx) => Console.WriteLine("Action triggered");

            builder.RightHandSide().Action(action);

            rulesList.Add(builder.Build());
        }
        catch (Exception e)
        {
        }

        return rulesList;
    }

    public Expression CreateParameterExpression(Type type, string propertyName, Type type2, string propertyName2)
    {
        ParameterExpression pe = Expression.Parameter(type, "e");
        Expression left = Expression.Property(pe, type.GetProperty(propertyName));
        return Expression.Property(left, type2.GetProperty(propertyName2));
    }
}
c# asp.net-core-2.1 nrules
1个回答
0
投票

你有一个CreateParameterExpression方法,它应该创建一个属性访问表达式。但是在该方法中,您创建的参数表达式名称为“e”,这与您在规则中定义的任何模式都不对应。这会导致“未找到变量”异常。

您只需要一个MemberExpression来访问customerData属性,然后另一个访问嵌套属性,在RuleEngineEntity中配置。这是一个更新的BuildRule方法,它实现了必要的表达式树。

public List<IRuleDefinition> BuildRule(List<RuleEngineEntity> list)
{
    var builder = new NRules.RuleModel.Builders.RuleBuilder();
    builder.Name("CustomerDetail");

    var orGroup = builder.LeftHandSide().Group(GroupType.Or);

    foreach (var item in list)
    {
        var andGroup = orGroup.Group(GroupType.And);

        var modelPattern = andGroup.Pattern(typeof(RuleEngineRequestModel), item.Name);
        var modelParameter = modelPattern.Declaration.ToParameterExpression();
        var customerData = Expression.Property(modelParameter, nameof(RuleEngineRequestModel.customerData));

        var customerCondition = Expression.Lambda(
            Expression.GreaterThan(
                    Expression.Property(customerData, item.FieldName),
                    Expression.Constant(item.Value)),
                modelParameter);
        modelPattern.Condition(customerCondition);
    }

    Expression<Action<IContext>> action =
        ctx => Console.WriteLine("Action triggered");

    builder.RightHandSide().Action(action);

    var rule = builder.Build();
    return new List<IRuleDefinition> {rule};
}
© www.soinside.com 2019 - 2024. All rights reserved.