从IObservable转换为IEnumerable的Reactive Extensions

时间:2017-04-23 02:51:53

标签: c# .net system.reactive

给定一个Observable,它将在调用Subscribe后开始推送事件。如何将序列转换为IEnumerable。

2010年,Jon Skeet写下了他对RX的第一印象并写了这篇文章,这相当于我的需要。

public static List<T> ToList<T>(this IObservable<T> source) 
{ 
    List<T> ret = new List<T>(); 
    source.Subscribe(x => ret.Add(x)); 
    return ret; 
}

https://codeblog.jonskeet.uk/2010/01/16/first-encounters-with-reactive-extensions/

虽然这个解决方案可行但似乎应该有更好的方法。

我们真正感兴趣的是能够await以类似于Subscribe的方式使用observable。

await observable.ToList()

但是,这对我来说似乎不起作用。

我也研究过这两种方法

observable.ToEnumerable
observable.Next

更多信息

我打算用它来编写一些单元测试。

  1. 我正在使用ReplaySubject并使用测试替代品执行一系列操作。
  2. 通过OnNext
  3. 记录对替代品的来电
  4. 我可以获取调用列表并断言它们是正确的。

2 个答案:

答案 0 :(得分:3)

有趣的是,Skeet先生的实施非常糟糕。它不会阻塞,因此如果源恰好是重放主题(或类似主题),则只会将值泵入列表。因此对于大多数Observable Sequences,这只会返回一个空列表。 我确信乔恩知道这一点,但也许在翻译中迷失了。

ToList()是你想要的,所以我想你也许没有完成?如果您只想要已知数量的元素,那么Take(x).ToList()就足够了。

答案 1 :(得分:2)

修改

如果您无法按照以下说明完成信息流,那么使用await将无休止地等待。我会以其他方式测试。您可以查看Nuget Package Microsoft.Reactive.Testing,它包含一些强大的测试工具。或者只是使用Subscribe并在那里断言。

await等待观察者完成或错误。您可能只需要向OnCompleted添加ReactiveSubject来电,您就可以了。以下代码适用于我:

var rs = new ReplaySubject<int>();

rs.OnNext(1);
rs.OnNext(2);
rs.OnNext(3);
rs.OnCompleted();
var l = await rs.ToList();

//l is equivalent to  new List<int>() {1, 2, 3};