如何根据流值将Observable.Timer的元素添加到可观察流中?

时间:2014-06-05 14:39:55

标签: c# system.reactive reactive-programming

我希望标题足够清晰。我正在玩弄Rx的想法并遇到一个我不确定如何制作的问题。

我有一些原始形式的事件输入,比如{ 1, 2, 3, 4, 5, 1, 2, 3, 4 }被转换为某种新形式的输入,比如IType。让我们说,只要观察到数字2,计时器就会开始计时并将新的转换值(或者说,数字6)插入到流中,除非数字5是遇到了,在这种情况下取​​消了计时器。

我正在考虑构建一个从各种来源获取输入的状态机。如果我可以定时"那将是很好的。事件也是流的一部分。

代码如下,但基本上我目前仍然坚持使用Observable.Generate的一些想法(即使其看起来像Observable.Timer,但要返回/插入新事件到输入序列)和/或可能像Observable.TakeUntilObservable.Create和合并流,但我不确定是否有更好的方法,甚至如何在代码方面解决这个问题。

在代码方面,它可能是这样的

using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Reactive.Subjects;


namespace RxTesting
{

    public interface IType
    {
        int OriginalInput { get; set; }
    }


    public class SomeEvent: IType
    {
        public int OriginalInput { get; set; }
    }


    public class TimeEvent: IType
    {
        public int OriginalInput { get; set; }
    }

     class  Program
     {
         static  void  Main(string[] args)
         {
             //Here we should have one TimerEvent after the last "2" in the sequence.
             var input = new Subject<int>();
             input.Select(i => new SomeEvent { OriginalInput = i }).SomeTimerOperatorHere().Subscribe(Console.WriteLine);

             input.OnNext(1);
             input.OnNext(2);
             input.OnNext(3);
             input.OnNext(4);
             input.OnNext(5);
             input.OnNext(1);
             input.OnNext(2);
             input.OnNext(3);
             input.OnNext(4);

             input.Dispose();
             Console.ReadKey();
        }
    }
}

在控制台中,应该打印一个RxTesting.TimerEvent,因为只有一个2,之后没有5取消其效果。

1 个答案:

答案 0 :(得分:1)

这应该这样做 - 我认为你的TakeUntil想法是正确的。

我们正在过滤事件,仅包含OriginalInput为2的事件,并将每个事件投射到值为6的单值延迟流,如果OriginalInput为5的事件到达,则将其切断。得到的流流用SelectMany展平。

public static IObservable<IType> SomeTimerOperatorHere(
  this IObservable<SomeEvent> source)
{
  var delay = TimeSpan.FromSeconds(1);

  return Observable.Create<IType>(o => {

    var sourcePub = source.Publish().RefCount();

    return sourcePub
      .Where(x => x.OriginalInput == 2)
      .SelectMany(type => 
        Observable.Return(new TimeEvent{ OriginalInput = 6 })
                  .Delay(delay)
                  .TakeUntil(sourcePub.Where(x => x.OriginalInput == 5))
      ).Subscribe(o);
  });
}