我想检查一下我创建的IObservable
是否尊重&#34的礼貌;一旦我完成,我将取消订阅" 。乍一看,我的代码看起来有问题。但是,除了我的代码,并且只使用TestScheduler提供的Observable和Observer,它看起来像是'取消订阅'永远不会发生:
using Microsoft.Reactive.Testing;
using System.Reactive;
...
var ts = new TestScheduler();
var ob = ts.CreateObserver<int>();
var xs = ts.CreateColdObservable<int>(
new Recorded<Notification<int>>(1, Notification.CreateOnCompleted<int>())
);
xs.Subscribe(ob);
ts.AdvanceTo(2);
Assert.Equal(1, xs.Subscriptions.Single().Unsubscribe); //<-- Xunit no like
我最初怀疑是观察者,但我尝试使用找到here代码的变体,并且它有效,所以我现在认为Subscribe
在ColdObservable
上的实现{1}}行为不正确。
答案 0 :(得分:2)
不存在这样的礼貌。 4.3节中的RX design guideines建议你可以:
假设在 OnError 或 OnCompleted 消息后清理资源。
在4.4节中说你可以:
尽最大努力停止取消订阅的所有优秀工作
这些指南(“courtesies”)谈论的是运营商发布自己的资源以及尽快获得的资源。
在您的代码中,您没有针对这两种情况进行测试。 Unsubscribe
上的ITestableObservable
属性的目的是报告观察者取消订阅的时间是否明确处理,而不是在内部清理发生时 - 但是您没有存储这个句柄能够处理它:
xs.Subscribe(ob); /* return of handle ignored here */
所以你试图断言你已经放弃了你丢弃的订阅,而不是你订阅的可观察量清理了它可能已经取消的任何订阅和资源。
如果你想看到4.3 / 4.4的及时资源清理的效果,写一个像这样的扩展方法:
public static IObservable<T> SpyResourceCleanUp<T>(
this IObservable<T> source, IScheduler scheduler)
{
return Observable.Create<T>(obs =>
{
var subscription = source.Subscribe(obs);
return new CompositeDisposable(
subscription,
Disposable.Create(() => Console.WriteLine(
"Clean up performed at " + scheduler.Now.Ticks)));
});
}
并替换你的行:
xs.Subscribe(ob);
与
xs.SpyResourceCleanUp(ts).Subscribe(ob);
(在某些评论中编辑)
在我的测试中,我看到了我所期望的即时资源清理。通过此更改,您的测试现在将通过,因为SpyResourceCleanUp
只要OnCompletes()本身符合4.3的准则,就会取消订阅它的父(xs)。
这里可能不明显的是,Observable.Create
只要 订阅处理Dispose()的{{1}}方法或 IDisposable
或OnComplete()
。这就是OnError()
帮助您实现第4.3节的原因,以及为什么测试会随着更改的代码传递。
在封面下,Create
返回的AnonymousObservable<T> : ObservableBase<T>
订阅由AutoDetachObserver
as you can see here包裹。
即。您从Create
返回的Disposable
不是调用者获得的Observable.Create
- 他们会获得一个包装版本,可以在流终止或取消时调用您的 Dispose()。< / p>