使用CombineLatest关联多个组的三个事件流

时间:2017-04-17 14:24:57

标签: c# system.reactive reactive-programming

我有3个可观察的事件流 - 按日期顺序 - (主要事件,有关销售的事件和有关客户的事件) - 每个流包含一种与各种车辆相关的事件,每个事件都有一个vehicleID和其他各种事件属性。事件可以出现在一辆车上,然后是另一辆车等。所以基本上我试图根据VehicleID将三个独立的事件流关联在一起 - 这听起来像应该是直截了当的事情。我是任何形式的复杂可观察编程的新手,所以这证明相当困难。

我想在任何流上看到车辆的新事件时调用一个函数(我猜基本上是combineLatest)。我可以这样做,如果我过滤每个流只包含一个车辆的事件,所以Where,但我无法弄清楚如何GroupBy,然后得到每个组的最新。我想我想要合并这些流,但是在每组车辆上组合起来。

下面会打印我想要创建的所有对象,仅用于VehcileID = 1。我希望对所有车辆进行以下操作。如果我用每个VehcileID循环使用它,这将给我输出我想要的输出 - 但这看起来不像时髦的观察 - 一切都是流 - 我应该瞄准的禅宗状态。

Observable.CombineLatest(mainEvents.Where(a=>a.VehcileID==1),saleEventsGroup.Where(a=>a.VehcileID==1),customerEventsGroup.Where(a=>a.VehcileID==1),(main, sale, customer)=>{ 
        //Basically flattening various properties from latest state of the 3 streams for current vehicle with some mapping
        return ComplexObject(){};})       
        .Subscribe(Console.WriteLine);

如何为每辆车组合每个流的最新事件。

任何建议都将不胜感激

1 个答案:

答案 0 :(得分:2)

这个怎么样?我这里只做两个流,但这个想法很容易扩展到三个

   [TestMethod]
   public void GroupByWithMultipleStreams()
    {
        Subject<Notification> producer = new Subject<Notification>();
        Subject<RelatedToNotification> otherThingProducer = new Subject<RelatedToNotification>();            

        Observable.Merge(
            producer.Select(n => new { Id = n.Id, notification = n, relatedNotification = (RelatedToNotification)null }),
            otherThingProducer.Select(rn => new { Id = rn.NotificationId, notification = (Notification)null, relatedNotification = rn }))
            .GroupBy(x => x.Id)
            .SelectMany(obs =>
            {
                return obs.Scan(new ComplexObject() { Id = obs.Key }, (acc, input) =>
                {
                    acc.Notification = input.notification ?? acc.Notification;
                    acc.Related = input.relatedNotification ?? acc.Related;
                    return acc;
                });
            })
            .Where(result => result.Notification != null && result.Related != null) // if you only want it to fire when everything has a value
            .Subscribe(result =>
            {
                //do something with the results here
            }
            );

        producer.OnNext(new Notification() { Id = 1, Version = 1 });
        producer.OnNext(new Notification() { Id = 1, Version = 2 });
        producer.OnNext(new Notification() { Id = 2, Version = 17 });
        producer.OnNext(new Notification() { Id = 1, Version = 3 });
        producer.OnNext(new Notification() { Id = 9, Version = 0 });
        producer.OnNext(new Notification() { Id = 9, Version = 1 });
        otherThingProducer.OnNext(new RelatedToNotification() { NotificationId = 2,  SomeData = "2data" });
        otherThingProducer.OnNext(new RelatedToNotification() { NotificationId = 2, SomeData = "2data1" });
        otherThingProducer.OnNext(new RelatedToNotification() { NotificationId = 9, SomeData = "9Data" });
        producer.OnNext(new Notification() { Id = 2, Version = 1 });

    }

    class ComplexObject
    {
        public int Id { get; set; }
        public Notification Notification { get; set; }
        public RelatedToNotification Related { get; set; }
    }

    class Notification
    {
        public int Id { get; set; }
        public int Version { get; set; }

        public string Name { get; set; }
    }

    public class RelatedToNotification
    {
        public int NotificationId { get; set; }
        public string SomeData { get; set; }
    }