如何使用Reactive Programming编写此代码?

时间:2016-12-16 17:34:07

标签: c# system.reactive

我刚刚开始搞乱反应式编程,而且我知道编写代码已经足够了,但还不足以弄清楚当我没有得到我所期望的时候会发生什么。除博客文章外,我还没有真正的导师。我还没有找到一个很好的解决方案来解决我遇到的问题,而且我对正确的方法感到好奇。

问题:

我需要得到一个Foo,它部分由一系列Bar对象组成。我从Web服务中获取Bar对象。所以我将每个Web服务调用表示为IObservable,在完成之前我期望从中获得0或1个元素。我想创建一个IObservable:

  • 订阅每个IObservable实例。
  • 等待最多2秒钟超时。
  • 当两个序列都完成或超时发生时:
    • 使用生成的任何Bar对象创建一个数组(可能有0。)
    • 使用Bar []生成Foo对象。

我用这段代码完成了这个:

public Foo CreateFoo() {

        var producer1 = webService.BarGenerator()
                                  .Timeout(TimeSpan.FromSeconds(2), Observable.Empty<Bar>());
        var producer2 = // similar to above

        var pipe = producer1.Concat(producer2);

        Bar[] result = pipe.ToEnumerable().ToArray();

        ...
}

由于很多原因,这看起来并不正确。最明显的是Concat()将连续地而不是并行地启动序列,因此超时为4秒。我并不十分关心它是否会阻止,它实际上对我正在使用的架构来说非常方便。我很好地将这种方法变成了IObservable的生成器,但是在这里我还有一些额外的注意事项,当我尝试时,它会带来一些挑战:

  1. 如果生成结果,我需要最终数组将producer1和producer2的结果放在那个顺序中。
  2. 我想使用TestScheduler验证超时但尚未成功,我显然根本不理解调度程序。
  3. 这最终是一个拉动模型,无论Foo在一个不同的点上需要它,在飞行中接收它是没有价值的。也许这会让答案倾向于“不要使用Rx&#34;”。说实话,我已经陷入困境,我转而使用基于任务的API。但我想知道如何用Rx来解决这个问题,因为我想学习。

1 个答案:

答案 0 :(得分:0)

    var pipe = producer1
        .Merge(producer2)
        .Buffer(Observable.Timer(TimeSpan.FromSeconds(2), testScheduler))
        .Take(1);

    var subscription = pipe
        .Select(list => new Foo(list.ToArray())
        .Subscribe(foo => {} /* Do whatever you want with your foo here.*/);

Buffer获取窗口期间发出的所有元素(在我们的例子中为两秒),并输出一个列表。

如果您想坚持拉模型,而不是订阅,您可以这样做:

var list = await pipe;
var foo = new Foo(list.ToArray());

//....