简体   繁体   English

IEnumerable <T> .Count()实际上适用于IObservable <T> ?

[英]Does IEnumerable<T>.Count() actually work for IObservable<T>?

Is there an example out there showing me how the Observable.Count<TSource> Method actually works? 是否有示例向我展示Observable.Count<TSource> Method实际工作方式? The examples I come up with appear to return a count wrapped in an observable instead of the expected count. 我提出的示例似乎返回包装在可观察值中的计数,而不是预期计数。

For example, I expect 1 to be returned from this: 例如,我希望从中返回1

System.Diagnostics.Debug.WriteLine((Observable.Return<string>("Hello world!")).Count());

Will 1 be returned in the future (because, after all, it is an asynchronous sequence)? 将来会返回1 (因为毕竟这是一个异步序列)? Or am I missing a few things fundamental? 还是我缺少一些基本的东西? As of this writing, I actually assume that .Count() will return the results of T and grow over time as long a results are pushed out. 在撰写本文时,我实际上假设.Count()将返回T的结果,并且随着时间的推移会不断增长。 Really? 真? Yes. 是。

The aggregate operators in Rx work a bit differently than in LINQ - they do not immediately return a value, they return a future result (ie we can only know what the final Count is once the Observable completes). Rx中的聚合运算符与LINQ中的聚合运算符有所不同-它们不会立即返回值,而是返回将来的结果 (即,一旦Observable完成,我们只能知道最终的Count是什么)。

So if you write: 因此,如果您写:

Observable.Return("foo").Count().Subscribe(x => Console.WriteLine(x));
>>> 1

because, after all, it is an asynchronous sequence 因为毕竟这是一个异步序列

This actually isn't exactly true. 这实际上并非完全正确。 Here, everything will be run immediately, as soon as somebody calls Subscribe . 在这里,只要有人打电话给Subscribe ,一切都将立即运行。 There is nothing asynchronous about this code above, there are no extra threads, everything happens on the Subscribe. 上面的代码没有异步的地方,没有多余的线程,所有事情都在订阅服务器上发生。

I think that using an observable that returns immediately and also using the async/await syntax as rasx did in the comments is confusing matters rather too much. 我认为使用可立即返回的observable 以及像rasx在注释中一样使用async / await语法会使事情变得相当混乱。

Let's create a stream with 5 elements that come back one every second and then complete: 让我们创建一个包含5个元素的流,这些元素每秒返回一次,然后完成:

private IObservable<long> StreamWith5Elements()
{
    return Observable.Interval(TimeSpan.FromSeconds(1))
                     .Take(5);
}

We can call it using async/await magic as in this LINQPad friendly example: 我们可以使用异步/等待魔术来调用它,如下面的LINQPad友好示例所示:

void Main()
{
    CountExampleAsync().Wait();
}

private async Task CountExampleAsync()
{
    int result = await StreamWith5Elements().Count();
    Console.WriteLine(result);
}

But it's misleading what's going on here - Count() returns an IObservable<int> , but Rx is super-friendly with await and converts that result stream into a Task<int> - and the await then hands back that task's int result. 但这误导了这里发生的事情IObservable<int> Count()返回IObservable<int> ,但是Rx对await超级友好,并将结果流转换成Task<int> -然后await将该任务的int结果移回。

When you use await against an IObservable<T> , you are implicitly saying that you expect that observable to call OnNext() with a single result and then call OnComplete() . 当对IObservable<T>使用await时,您隐式地说,您希望observable可以使用单个结果调用OnNext() ,然后调用OnComplete() What actually happens is that you will get a Task<T> that returns the last value sent before the stream terminated. 实际发生的情况是,您将获得Task<T> ,该Task<T>返回在流终止之前发送的最后一个值。 (Similar to how AsyncSubject<T> behaves). (类似于AsyncSubject<T>行为)。

This is useful because it means any stream can be mapped to a Task , but it does require some careful thought. 这很有用,因为它意味着任何流都可以映射到Task ,但是确实需要仔细考虑。

Now, the above example is equivalent to the following more traditional Rx: 现在,上面的示例等效于以下更传统的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();
}

Here you can see that Count() is indeed returning a stream of int - to provide an asynchronous count. 在这里,您可以看到Count()确实返回了int流-提供异步计数。 It will return only when the source stream completes. 仅在源流完成时才返回。

In the early days of Rx, Count() was in fact synchronous. 在Rx的早期,Count()实际上是同步的。

However, that's not a terribly useful state of affairs since it "Exits the Monad" - ie brings you out of IObservable<T> and prevents you from further composition with Rx operators. 但是,这并不是一个非常有用的状态,因为它“退出Monad”-即使您脱离IObservable<T>并阻止您进一步使用Rx运算符。

Once you start "thinking in streams", the asynchronous nature of Count() is quite intuitive really, since of course you can only provide a count of a stream when it's finished - and why hang around for that?? 一旦开始“在流中思考”,Count()的异步特性实际上就非常直观了,因为当然,您只能在流完成时提供一个流的计数,为什么还要为此而徘徊呢? :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM