在可观察链中执行基于任务的方法 => IObservable<IObservable<Unit>>



我有很多代码是被动的,但需要调用基于任务的方法。

例如,在这个片段中,PracticeIdChanged是一个IOobservable。当PracticeIdChanged启动时,我希望系统通过重新加载一些东西来做出反应,并拥有如下代码:

PracticeIdChanged.Subscribe(async x => {
SelectedChargeInfo.Item = null;
await LoadAsync().ConfigureAwait(false);
});

尽管它看起来工作正常,但我在Subscribe中收到了关于执行异步代码的警告。此外,我认为这是一种代码气味,因为我正在混合两个独立的线程模型,我认为稍后可能会对我产生影响。

像这样的重构在没有.Merge((、.Switch((或.Concat((等组合方法的情况下也能工作(甚至(

PracticeIdChanged
.Do(_ => SelectedChargeInfo.Item = null)
.Select(_ => LoadAsync().ToObservable())
.Subscribe();

PracticeIdChanged激发LoadAsync方法时执行

选择结果为IObservable<I可观察>这看起来很奇怪。这可以吗?还是需要一些组合功能,如.Merge或.Switch((

在许多地方,我使用SelectMany来执行基于任务的方法,但它需要返回Task,这需要在上面的示例中更改基于任务方法的签名,而我不想这样做

这取决于您希望从结果序列中获得什么样的通知,以及在出现错误时需要什么样的行为。在您的示例中,您.Subscribe()到序列,而不传递任何处理程序(onNext/onError/onCompleted(,这表明您不想收到任何通知。您不关心异步操作的完成,所有这些操作基本上都会被激发和遗忘。此外,一个异步操作的失败不会对其他操作产生影响:已经启动的异步操作将继续运行(它们不会被取消(,并且启动新的异步操作不会受到阻碍。最后,源序列(PracticeIdChanged(的失败将导致未处理的异常,这将使进程崩溃。如果这是你想要的行为,那么你当前的设置就是你需要的。

为了进行比较,让我们考虑一下这个设置:

await PracticeIdChanged
.Do(_ => SelectedChargeInfo.Item = null)
.Select(_ => Observable.FromAsync(ct => LoadAsync(ct)))
.Merge()
.DefaultIfEmpty();

此设置假定LoadAsync方法具有CancellationToken参数。生成的序列为await。当所有LoadAsync操作都已完成,或其中任何一个操作失败,或源序列失败时,await将完成。如果出现故障,所有当前运行的异步操作都会收到一个取消信号,这样它们就可以快速退出。await而不是等待它们的完成。只有发生的第一个错误才会作为异常传播。可以通过将await封装在try/catch块中来处理此异常。不可能出现无法捕获、进程崩溃、未处理的异常。

链末端的DefaultIfEmpty的目的是在源序列发射零元素的情况下防止InvalidOperationException。这是一个解决这个奇怪的";特征";空的可观察序列,在同步或异步等待时抛出。

相关内容

  • 没有找到相关文章

最新更新