测试取消一个简单的observable不会调用onError

时间:2017-09-15 09:17:49

标签: c# async-await system.reactive

鉴于以下内容:

为什么RECT barRect; barRect.top = 0; barRect.left = 0; barRect.bottom = 100; barRect.right = 1020; m_pMainWnd->RepositionBars(0, 0, 0, 2, &barRect); m_pMainWnd->GetTopLevelFrame()->RecalcLayout(); m_pMainWnd->DrawMenuBar(); for (POSITION pos = m_pMainWnd->GetTopLevelFrame()->m_listControlBars.GetHeadPosition(); pos != NULL;) { CControlBar* controlBar = reinterpret_cast<CControlBar*>(m_pMainWnd->GetTopLevelFrame()->m_listControlBars.GetNext(pos)); controlBar = nullptr; //Let's see what we can do with this. Is the menuBar a ControlBar? Didnt think so. } m_pMainWnd->RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 中的OnError处理程序从未调用过?

Subscribe

3 个答案:

答案 0 :(得分:5)

当您在令牌上调用Cancel时,您(通过令牌并因此“拥有”取消的订阅者)基本上说“我不再对事件感兴趣,包括OnError()”。< / p>

在幕后,Rx在observable和观察者之间插入AutoDetachObserver,显式吞下所有其他事件。

此行为是设计使然。

在您订阅时,

OnError()可以告诉您有关失败的信息。取消令牌(取消订阅观察者)后,您不再订阅并且不再接收任何事件。换句话说,取消订阅不是错误。并且取消observable中的令牌不是错误或是一种有效的通信方式 - 调用OnError()

答案 1 :(得分:3)

在观察者OnError(以及其他函数)的基本实现中包含:

if (Interlocked.Exchange(ref this.isStopped, 1) == 0)
{
    this.OnErrorCore(error);
}

isStopped设置为&#34;已停止&#34;当令牌取消时。观察员负责取消过程,不需要手动控制它。

如果您将OnNext代码更改为

,则可以轻松检查
if(str == "B")
    token.Cancel(); // cancel after the second iteration.

结果将是:

enter image description here

即使您删除了if语句。取消令牌后,不会调用任何继承的函数

var observable = Observable.Create<string>(
    async (o, c) =>
        {
            var strings = new[] { "A", "B", "C" };

            foreach (var s in strings)
            {
                await Task.Delay(100);
                o.OnNext(s);
            }
            o.OnCompleted();
        });

因此,请记住,当令牌被取消时(逻辑上它不是错误)不要将逻辑移动到任何事件实现,而是在调用者代码中执行所需的取消逻辑:

if (c.IsCancellationRequested)
{
    // exception thrown here.
    Console.WriteLine("cancelled");
    tcs.SetResult(true); // instead of throwing exceptions
    // some other clean up code or/and return statement
} 

答案 2 :(得分:3)

建立詹姆斯所写的内容:Rx订阅的两部分,可观察(发布者)和观察者(订阅者)。当您使用取消令牌订阅到observable时,您有效地告诉订阅者取消订阅。

在您的方案中,这意味着一旦取消,订阅者就会停止收听。因此,onError通知不会被收听,因此Task永远不会完成。

如果删除传递给订阅调用的token,则onError将按预期流向订阅。