gpt4 book ai didi

c# - 为什么 Observable.Finally 在 Observable.Generate 完成时不被调用?

转载 作者:行者123 更新时间:2023-12-04 12:26:43 26 4
gpt4 key购买 nike

我需要在两个状态之间交替,每个状态都有不同的间隔时间。
我能想到的最好的方法是使用 Reactive Extensions 的 Observable.Generate
这非常棒。

从我在 msdn 和其他网站上读到的内容来看,Observable.Finally() 应该触发,如果
observable “优雅地或异常地终止”。我正在测试以下代码
(在 LINQPad 中)查看它是如何工作的,但我根本无法让 .Final() 触发。

var ia = TimeSpan.FromSeconds(1);
var ib = TimeSpan.FromSeconds(.2);
var start = DateTime.UtcNow;
var ct = new CancellationTokenSource();

var o = Observable.Generate(
true,
// s => !ct.IsCancellationRequested,
s => (DateTime.UtcNow-start) < TimeSpan.FromSeconds(3) && !ct.IsCancellationRequested,
s => !s,
s => s ? "on" : "off",
s => s? ib : ia)
// .TakeUntil(start+TimeSpan.FromSeconds(3))
.Concat(Observable.Return("end"));


o.Subscribe( s=> s.Dump(), ct.Token);
var t = o.ToTask(ct.Token);


t.ContinueWith(x => x.Dump("done"));
o.Finally(() => "finallY".Dump()); // never gets called?

Thread.Sleep(10000);
ct.Cancel();

如果我使 Thread.Sleep 10s,可观察序列完成并且 Task.ContinueWith 触发,
但不是 .Finally()。

如果我使 Thread.Sleep 2s,可观察序列被取消并且 Task.ContinueWith 再次触发,
但不是 .Finally()。

为什么不?

最佳答案

查看Finally的返回类型方法;应该给你一个提示。就像 Concat方法返回一个新的 IObservable将新序列连接到它,但不会更改原始序列 Finally方法返回一个新的 IObservable有最后的行动,但你订阅了原来的IObservable .将以下行放在您的 Subscribe 前面打电话,它会工作。

o = o.Finally(() => "finallY".Dump());

我同意这是一个奇怪的 API 选择;我会想到 Finally更类似于 Subscribe比到 Concat .你订阅了最后的“事件”;奇怪的是,API 强制您创建一个全新的 IObservable,然后订阅它只是为了获得 Finally要发生的事情。此外,它允许一个潜在的错误(如果我们在您的问题中使用该函数,则很明显),如果您订阅该新 IObservable 两次,您的 Finally函数将执行两次。因此,您必须确保您的订阅之一在“最终”IObservable 上,而其他订阅都在原始订阅上。只是看起来不寻常。

我猜想的方式是 Finally不是要修改 observable,而是要修改订阅本身。即,他们通常不希望您制作具有 Finally 的可公开访问的命名 observables事情( var o = Observable.[...].Finally(...); )而不是它意味着与订阅调用本身一致( var subscription = o.Finally(...).Subscribe(...); )

关于c# - 为什么 Observable.Finally 在 Observable.Generate 完成时不被调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17578722/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com