NRules - Organizing Rules

550 views Asked by At

When organizing rules for NRules, is it necessary to only have 1 When/Then group in a file?

I have one rule that looks at 3 conditions (fact matches), is flagA = false, inputA = one of a list of values, and inputB = a single value. When all true, set flagA to true. I got that one working,then wanted to add the second rule.

The second rule is when flagA is false and flagB is true then set flagA to true.

Do these two rules need to be in separate .cs files or can they be together in one.

I looked at the ".Or" option, but I am not good enough with fluent to figure out what it is doing.

Thanks for your help, Toom

1

There are 1 answers

6
Sergiy Nikolayev On

In NRules an instance of a class that inherits from NRules.Fluent.Dsl.Rule is one rule. You can put multiple rule classes in one .cs file or different files, it does not matter - each class is still a separate rule.

In that rule class, you normally would specify When and Then sections only once. If you specify them multiple times, all conditions would still be combined into a single set using and group. Actions would also be merged into a single set.

So:

public class Rule1: Rule
{
    public override void Define()
    {
        When()
            .Match<A>();
        Then()
            .Do(_ => X());

        When()
            .Match<B>();
        Then()
            .Do(_ => Y());
    }
}

is exactly the same as

public class Rule1: Rule
{
    public override void Define()
    {
        When()
            .Match<A>()
            .Match<B>();
        Then()
            .Do(_ => X())
            .Do(_ => Y());
    }
}

In other words, both examples above create just a single rule that matches both A and B, and if both those facts match, then both X and Y methods are executed.

If you want that to be two independent rules, then put those different When/Then sections into different rule classes.

public class Rule1: Rule
{
    public override void Define()
    {
        When()
            .Match<A>();
        Then()
            .Do(_ => X());
    }
}

public class Rule2: Rule
{
    public override void Define()
    {
        When()
            .Match<B>();
        Then()
            .Do(_ => Y());
    }
}

UPDATE: If you wanted to connect conditions A and B with an OR, you could do it like below. Here the rule will fire if ((A OR B) AND C):

public class Rule1: Rule
{
    public override void Define()
    {
        When()
            .Or(x => x
                .Match<A>()
                .Match<B>())
            .Match<C>();
        Then()
            .Do(_ => Z());
    }
}