![](/img/trans.png)
[英]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.