Observable.Do永远不会触发,即使底层IObservable发生变化

c#

我在 ReactiveUI 中获得了一些速成课程,并且System.Reactive.Linq在发现我需要的 UI 库后将其用于所有内容。大多数情况下这似乎很容易理解,但是有一个操作没有做任何事情。

我有一个控件,我需要在两个地方使用它的值。我有一个IObservable<T>代表它的价值,我使用如下:

案例 1:我需要将一个值与另一个 observable 值相结合,从而为另一个 observable 提供一个值。所以我Observable.CombineLatest(myObservable, otherObservable, (m, o) => ProduceValue(m, o))完全按照预期使用此更新生成它
。由此,我知道这myObservable是正确触发更新。

情况 2:我需要在其他地方使用这个值,在不可观察的上下文中。所以:myObservable.Do(v => UpdateViewModelWith(v))这永远不会触发。 我已经通过在 lambda 中放置一个断点并在调试器下运行它来验证这一点。

从案例 1 我知道 observable 正在正确触发。据我了解,observables 在概念上很像 Events,(有一堆机制让它们感觉更像IEnumerables,)并且 Events 完全能够接受多个侦听器,所以事实上它们不应该有两个成为问题。(通过更改设置两个侦听器的顺序进行验证,这不会导致观察到的行为发生变化。)那么什么会导致案例 2 永远不会运行呢?

回答

@Erwin 的回答很接近。简单说一下:

Do和大多数 Rx 相关的函数一样,是一个操作符。运营商没有订阅就什么都不做。例如:

var source = Observable.Range(0, 5);
var squares = source.Select(i => i * i);
var logged = squares.Do(i => Console.WriteLine($"Logged Do: {i}));

var sameThingChained = Observable.Range(0, 5)
    .Select(i => i * i)
    .Do(i => Console.WriteLine($"Chained Do: {i}));

//until here, we're in no-op land. 

Range,SelectDo都是运营商,没有订阅就什么都不做。如果您希望其中的任何一项执行任何操作,则需要订阅。

var subscription = logged.Subscribe(i => Console.Writeline($"Subscribe: {i}");

输出:

Logged Do: 0
Subscribe: 0
Logged Do: 1
Subscribe: 1
Logged Do: 4
Subscribe: 4
Logged Do: 9
Subscribe: 9
Logged Do: 16
Subscribe: 16

通常,副作用代码(非功能代码)应该驻留在Subscribe函数中。Do最适合用于日志记录/调试。所以如果我想记录原始的非平方整数,我可以这样做。

var chainedSub = Observable.Range(0, 5)
    .Do(i => Console.WriteLine($"Original int: {i}"));
    .Select(i => i * i)
    .Subscribe(i => Console.Writeline($"Subscribe: {i}");

在纯 Rx.NET(没有 ReactiveUI)中,只有一种方法可以获取订阅:各种Subscribe重载。但是,ReactiveUI 确实有一堆函数可以自己创建订阅,因此您不必处理它们(例如ToProperty)。如果您使用的是 ReactiveUI,那么这些可能比Subscribe.


以上是Observable.Do永远不会触发,即使底层IObservable发生变化的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>