NRules:为复杂类型构建规则

NRules: building a rule for complex types

给定以下域模型

public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }
  public List<Car> Cars { get; set; }
}
public class Car
{
    public int Year { get; set; }
    public string Make { get; set; }
}

是否可以编写一条规则,对 30 岁以下的人拥有的所有 2016 年以后的新车执行操作?我这样做只是将 Person 对象作为事实插入。

Person p1 = new Person("Jim", 31);
p1.Cars = GetCars(4);
Person p2 = new Person("Bob", 29);
p2.Cars = GetCars(4);

session.Insert(p1);
session.Insert(p2);

我试过类似的方法。我猜如果我在 Car 中添加一个引用回到拥有它的 Person ,我可以让它工作,但我的实际用例会使这变得困难。我希望我只是错过了一些东西。

public class CarTest : Rule
{
  public override void Define()
  {
    Person person = null;           
    IEnumerable<Car> cars = null;

    When()
      .Match<Person>(() => person, p => p.Age < 30)
      .Query(() => cars, x => x
         .Match<Car>(c => c == person.Cars.Find(f=> f.Make == c.Make && f.Year == c.Year), c => c.Year > 2016)
         .Collect()
         .Where(p => p.Any()));
    Then()
      .Do(ctx => DoSomethingWithNewCarsThatBelongToYoungPeople(cars));

  }

  private static void DoSomethingWithNewCarsThatBelongToYoungPeople(IEnumerable<Car> cars)
  {
     foreach (var car in cars)
     {
        //Do Something
     }
  }
}

通过连接处理复杂匹配的聚合的最佳方法是将其分解为两个规则并使用前向链接。

第一条规则将给定的年轻人与他们认为新的汽车相匹配。然后它会产生一个新的事实来包装结果。

public class YoungPersonWithNewCarRule : Rule
{
    public override void Define()
    {
        Person person = null;
        IEnumerable<Car> cars = null;

        When()
            .Match(() => person, p => p.Age < 30)
            .Let(() => cars, () => person.Cars.Where(c => c.Year > 2016))
            .Having(() => cars.Any());
        Then()
            .Yield(ctx => new YoungPersonWithNewCar(person, cars));
    }
}

public class YoungPersonWithNewCar
{
    private readonly Car[] _cars;

    public Person Person { get; }
    public IEnumerable<Car> Cars => _cars;

    public YoungPersonWithNewCar(Person person, IEnumerable<Car> cars)
    {
        _cars = cars.ToArray();
        Person = person;
    }
}

第二条规则匹配第一条规则产生的事实并将它们聚合到一个集合中。

public class YoungPeopleWithNewCarsHandlingRule : Rule
{
    public override void Define()
    {
        IEnumerable<YoungPersonWithNewCar> youngPeopleWithNewCars = null;

        When()
            .Query(() => youngPeopleWithNewCars, q => q
                .Match<YoungPersonWithNewCar>()
                .Collect()
                .Where(c => c.Any()));
        Then()
            .Do(ctx => DoSomethingWithNewCarsThatBelongToYoungPeople(youngPeopleWithNewCars));
    }

    private void DoSomethingWithNewCarsThatBelongToYoungPeople(IEnumerable<YoungPersonWithNewCar> youngPeopleWithNewCars)
    {
        //
    }
}