在 NRULES 中实现正向链接的最佳方法



我想根据上一个规则的结果运行一个规则。如何使用正向链接实现此功能?我不想为每个规则创建不同的类对象来实现正向链接。

在此示例中,仅为这一个规则创建了一个 InstantDiscount 对象,以实现正向链接。

public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
Double total = Double.NaN;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Query(() => orders, x => x
.Match<Order>(
o => o.Customer == customer,
o => o.IsOpen)
.Collect())
.Let(() => total, () => orders.Sum(x => x.Amount))
.Having(() => total > 1000);
Then()
.Yield(_ => new InstantDiscount(customer, total * 0.05));
}
}
public class PrintInstantDiscountRule : Rule
{
public override void Define()
{
InstantDiscount discount = null;
When()
.Match(() => discount);
Then()
.Do(_ => Console.WriteLine("Customer {0} has instant discount of {1}", 
discount.Customer.Name, discount.Amount));
}
}

正向链接是一个规则以激活其他规则的方式更改规则引擎的工作内存的过程。这可以通过将新事实插入规则引擎(使用 Yield 或 IContext.Insert in NRules)或通过更改一些现有事实(使用 IContext.Update)来实现。

下面是原始示例,重新表述以将折扣附加到"客户"事实,然后更新该事实以实现正向链接。

public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
Double total = Double.NaN;
When()
.Match<Customer>(() => customer, c => c.IsPreferred, c => !c.DiscountPercent.HasValue)
.Query(() => orders, x => x
.Match<Order>(
o => o.Customer == customer,
o => o.IsOpen)
.Collect())
.Let(() => total, () => orders.Sum(x => x.Amount))
.Having(() => total > 1000);
Then()
.Do(ctx => ApplyDiscount(customer, 0.05))
.Do(ctx => ctx.Update(customer));
}
private static void ApplyDiscount(Customer customer, double discount)
{
customer.DiscountPercent = discount;
}
}
public class DicsountNotificationRule : Rule
{
public override void Define()
{
Customer customer = null;
When()
.Match(() => customer, c => c.DiscountPercent.HasValue);
Then()
.Do(_ => Console.WriteLine("Customer {0} has instant discount of {1}%", 
customer.Name, customer.DiscountPercent));
}
}

通过更新现有事实进行正向链接时,必须注意不要重新激活更新事实的规则,以避免不需要的递归。有几种机制可以控制 NRules 中的递归:

  • 以更新使规则条件无效的方式写入条件(这就是我们在上面示例中所做的;一旦设置了折扣,规则将不再匹配)
  • 对规则使用"重复性"属性以防止重新触发
  • 使用议程筛选器仅在匹配事实发生某些更改时激活规则。

后两个选项在 NRules 文档中进行了介绍。

最新更新