如何在 NRules 中进行最佳写入规则定义
How to do optimal write rule definition in NRules
NRules SimpleRule 的代码定义了以下规则:
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Collect<Order>(() => orders,
o => o.Customer == customer,
o => o.IsOpen,
o => !o.IsDiscounted);
Then()
.Do(ctx => ApplyDiscount(orders, 10.0))
.Do(ctx => LogOrders(orders))
.Do(ctx => orders.ToList().ForEach(ctx.Update));
}
...
}
我想知道为什么条件是单独的参数而不是仅使用 && 运算符,即以下是否会产生相同的效果?
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Collect<Order>(() => orders,
o => o.Customer == customer && o.IsOpen && !o.IsDiscounted);
Then()
.Do(ctx => ApplyDiscount(orders, 10.0))
.Do(ctx => LogOrders(orders))
.Do(ctx => orders.ToList().ForEach(ctx.Update));
}
...
}
这两个定义应该做同样的事情。 Collect 方法需要一个 Expression<Func<T, bool>>
的数组。第一个将其拆分为 3 个单独的条件,而第二个仅使用一个条件(与组合)。
我认为这是一个品味问题,你更喜欢哪一个。但是对于第一个,哪些条件是相关的很清楚,您可以轻松地删除或添加条件(通过注释//)。
提供由“&&”分隔的组件的单个条件表达式与提供多个条件表达式之间存在差异。
在幕后,规则被编译成一个网络(rete 网络),每个条件都由网络中的一个节点表示。当多个规则共享相同的条件子集时,这些节点在网络中共享,从而产生效率(因为要评估的条件更少)。由于节点共享,提供多个条件表达式可为引擎提供更多优化机会。
另一个区别是条件短路。使用“&&”运算符提供单个条件表达式时,标准 C# 条件短路适用。如果第一个条件为假,则不评估第二个条件。当提供多个条件时,这不一定是真的(因为优化是由引擎在不同级别完成的)。
最佳做法是使用多个条件表达式,而不是使用带有“&&”的单个条件表达式。
NRules SimpleRule 的代码定义了以下规则:
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Collect<Order>(() => orders,
o => o.Customer == customer,
o => o.IsOpen,
o => !o.IsDiscounted);
Then()
.Do(ctx => ApplyDiscount(orders, 10.0))
.Do(ctx => LogOrders(orders))
.Do(ctx => orders.ToList().ForEach(ctx.Update));
}
...
}
我想知道为什么条件是单独的参数而不是仅使用 && 运算符,即以下是否会产生相同的效果?
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Collect<Order>(() => orders,
o => o.Customer == customer && o.IsOpen && !o.IsDiscounted);
Then()
.Do(ctx => ApplyDiscount(orders, 10.0))
.Do(ctx => LogOrders(orders))
.Do(ctx => orders.ToList().ForEach(ctx.Update));
}
...
}
这两个定义应该做同样的事情。 Collect 方法需要一个 Expression<Func<T, bool>>
的数组。第一个将其拆分为 3 个单独的条件,而第二个仅使用一个条件(与组合)。
我认为这是一个品味问题,你更喜欢哪一个。但是对于第一个,哪些条件是相关的很清楚,您可以轻松地删除或添加条件(通过注释//)。
提供由“&&”分隔的组件的单个条件表达式与提供多个条件表达式之间存在差异。
在幕后,规则被编译成一个网络(rete 网络),每个条件都由网络中的一个节点表示。当多个规则共享相同的条件子集时,这些节点在网络中共享,从而产生效率(因为要评估的条件更少)。由于节点共享,提供多个条件表达式可为引擎提供更多优化机会。
另一个区别是条件短路。使用“&&”运算符提供单个条件表达式时,标准 C# 条件短路适用。如果第一个条件为假,则不评估第二个条件。当提供多个条件时,这不一定是真的(因为优化是由引擎在不同级别完成的)。
最佳做法是使用多个条件表达式,而不是使用带有“&&”的单个条件表达式。