1

我在 ReactiveUI 中学习了一些速成课程,并System.Reactive.Linq在发现我需要的 UI 库将它用于所有事情之后。在大多数情况下,这似乎是可以理解的,但是有一个操作没有做任何事情。

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

案例1:我需要将一个值与另一个可观察值结合起来,将一个值提供给另一个可观察值。所以我 Observable.CombineLatest(myObservable, otherObservable, (m, o) => ProduceValue(m, o))完全按照预期使用此更新来制作它。由此,我知道这myObservable是正确触发更新。

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

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

4

2 回答 2

5

@Erwin 的答案很接近。只是为了详细说明:

Do,与大多数与 Rx 相关的函数一样,是operator。没有订阅,运营商什么都不做。例如:

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,Select并且Do都是操作符,没有订阅就什么都不做。如果你想让其中任何一个做任何事情,你需要订阅。

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.

于 2021-07-18T16:25:21.637 回答
4

我猜你正在使用一个没有任何订阅者的可观察对象,这意味着它永远不会触发并且Do永远不会被激活。

您想要的功能可能是IObservable<T>.Subscribe<T>(Action<T> action)

myObservable.Subscribe(v => UpdateViewModelWith(v))

Do和之间的区别在于SubscribeDo是一个副作用。这是在管道一侧发生的事情:“给我一些值,哦,顺便说一句,在一边做这个。” 但如果没有管道,则永远不会发送值。

另一方面Subscribe注册一个观察者。它实际上创建了一个管道,通过告诉 observable:“嘿,有人在看,发送东西!”

为了更好地理解它的含义,您还可以查看返回类型:

  • Do返回 an IObservable<T>,因为 observable 没有被消耗。
  • Subscribe返回一个IDisposable, 因为它注册了一个观察者。

重要提示:确保包含using System,否则您只会看到IObservable<T>.Subscribe<T>(IObserver<T> observer).

顺便说一句,就在今天早上,我也对 Do 和 Subscribe 感到困惑,并在非常好的Reactive Slack上获得了帮助。如果您正在使用 Rx 或 ReactiveUI,我强烈建议您加入!

于 2021-07-18T15:46:52.170 回答