[英]Turn an IObservable<IEnumerable<T>> into an IEnumerable<IObservable<T>>
[英]Does IEnumerable<T>.Count() actually work for IObservable<T>?
是否有示例向我展示Observable.Count<TSource> Method
实际工作方式? 我提出的示例似乎返回包装在可观察值中的计数,而不是预期计数。
例如,我希望从中返回1
:
System.Diagnostics.Debug.WriteLine((Observable.Return<string>("Hello world!")).Count());
将来会返回1
(因为毕竟这是一个异步序列)? 还是我缺少一些基本的东西? 在撰写本文时,我实际上假设.Count()
将返回T
的结果,并且随着时间的推移会不断增长。 真? 是。
Rx中的聚合运算符与LINQ中的聚合运算符有所不同-它们不会立即返回值,而是返回将来的结果 (即,一旦Observable完成,我们只能知道最终的Count是什么)。
因此,如果您写:
Observable.Return("foo").Count().Subscribe(x => Console.WriteLine(x));
>>> 1
因为毕竟这是一个异步序列
这实际上并非完全正确。 在这里,只要有人打电话给Subscribe
,一切都将立即运行。 上面的代码没有异步的地方,没有多余的线程,所有事情都在订阅服务器上发生。
我认为使用可立即返回的observable 以及像rasx在注释中一样使用async / await语法会使事情变得相当混乱。
让我们创建一个包含5个元素的流,这些元素每秒返回一次,然后完成:
private IObservable<long> StreamWith5Elements()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Take(5);
}
我们可以使用异步/等待魔术来调用它,如下面的LINQPad友好示例所示:
void Main()
{
CountExampleAsync().Wait();
}
private async Task CountExampleAsync()
{
int result = await StreamWith5Elements().Count();
Console.WriteLine(result);
}
但这误导了这里发生的事情IObservable<int>
Count()
返回IObservable<int>
,但是Rx对await
超级友好,并将结果流转换成Task<int>
-然后await将该任务的int
结果移回。
当对IObservable<T>
使用await时,您隐式地说,您希望observable可以使用单个结果调用OnNext()
,然后调用OnComplete()
。 实际发生的情况是,您将获得Task<T>
,该Task<T>
返回在流终止之前发送的最后一个值。 (类似于AsyncSubject<T>
行为)。
这很有用,因为它意味着任何流都可以映射到Task
,但是确实需要仔细考虑。
现在,上面的示例等效于以下更传统的Rx:
void Main()
{
PlainRxCountExample();
}
private void PlainRxCountExample()
{
IObservable<int> countResult = StreamWith5Elements().Count();
countResult.Subscribe(count => Console.WriteLine(count));
/* block until completed for the sake of the example */
countResult.Wait();
}
在这里,您可以看到Count()
确实返回了int流-提供异步计数。 仅在源流完成时才返回。
在Rx的早期,Count()实际上是同步的。
但是,这并不是一个非常有用的状态,因为它“退出Monad”-即使您脱离IObservable<T>
并阻止您进一步使用Rx运算符。
一旦开始“在流中思考”,Count()的异步特性实际上就非常直观了,因为当然,您只能在流完成时提供一个流的计数,为什么还要为此而徘徊呢? :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.