微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

我有一个控件,我需要在两个地方使用它的值。我有一个 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. 

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

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<T>.Subscribe<T>(Action<T> action):

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

DoSubscribe 的区别在于 Do 是副作用。这是在管道一侧发生的事情:“向我传递一些值,哦,顺便说一下,在一侧执行此操作。”但是如果没有管道,则永远不会发送这些值.

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

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

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。