How to do optimal write rule definition in NRules

2.1k views Asked by At

The code of NRules SimpleRule define the following rule:

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));
    }
        ...
}

I am wondering why the conditions are seperate pareameters in stead of just using && operator i.e. will the following have the same effect?

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));
    }
        ...
}
2

There are 2 answers

1
Jehof On BEST ANSWER

The two definitions should do the same thing. The Collect method expects an array of Expression<Func<T, bool>>. The first one splits it up into 3 separate conditions, while the second uses only one condition (And-combined).

I think it is a matter of taste, which one you prefer. But with the first one it is much cleared which conditions are relevant and you can easily remove or add conditions (via commenting //).

0
Sergiy Nikolayev On

There are differences between supplying a single condition expression with components separated by a '&&' and supplying multiple condition expressions.

Behind the scenes the rules are compiled into a network (rete network), and each condition is represented by a node in the network. When multiple rules share the same subset of conditions, those nodes are shared in the network, which yields efficiency (since there are fewer conditions to evaluate). Supplying multiple condition expressions gives the engine more opportunities for optimization due to node sharing.

Another difference is condition short-circuiting. When supplying a single condition expression using '&&' operator, the standard C# condition short-circuiting applies. If the first condition is false, the second one is not evaluated. This is not necessarily true when supplying multiple conditions (since optimization is done by the engine at a different level).

The best practice is to use multiple conditional expressions instead of a single one with '&&'.