C# RX Switch()的订阅和取消订阅订单
所以我写了一份我遇到的问题的草稿。我有一个IObservableC# RX Switch()的订阅和取消订阅订单,c#,.net,system.reactive,reactive-programming,C#,.net,System.reactive,Reactive Programming,所以我写了一份我遇到的问题的草稿。我有一个IObservable包含我的流,我想使用switch从中获取最新的项目,但是我的问题可以通过下面的代码清楚地演示: var obs = Observable.Create<IObservable<int>>(sub => { var item = Observable.Create<int>(innersub => {
var obs = Observable.Create<IObservable<int>>(sub =>
{
var item = Observable.Create<int>(innersub =>
{
var count = 0;
return Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(x => innersub.OnNext(count++));
}).Publish().RefCount();
return Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(x => sub.OnNext(item));
});
obs.Switch().Subscribe(x => Console.WriteLine(x));
上面的测试用例显示,当与Publish.RefCount结合使用时,交换机首先取消订阅,然后订阅新项目
我想要的是一个连续的数字流上升,但测试显示,该项目是在新的订阅命中前首先处理,我失去了计数,必须重新开始
如果项目是相同的,并且使用了refcount,那么我希望先进行订阅,这样refcount会很高兴,然后处理旧订阅。这是RX默认可以演示的行为,还是需要一些预兆才能正确?我相信我可以基于RX源代码的精简版本编写一个足够简单的扩展方法,但如果它已经存在,或者有更好的方法,我想先知道
编辑:编写的代码是一个简单的示例,用一种简单的方式演示了这个问题。我实际拥有的是一个定期发布一个新的可观察对象的可观察对象,它有不同的过滤器,但最终归结为相同的发布/引用计数可观察对象。where子句更改,或者select执行不同的操作。真正的用途是将几个流合并,所以我对我的逻辑和我对问题的结论很有信心。我很清楚,我的示例可以简化。您必须查看源,因为前一个可观察对象在当前可观察对象被订阅之前被释放。这就是开关的工作原理 如果在新订阅后处理Rx,则代码的意图似乎等同于简单地执行此操作:
var obs = Observable.Create<int>(innersub =>
{
var count = 0;
return Observable.Interval(TimeSpan.FromSeconds(2))
.Subscribe(x => innersub.OnNext(count++));
});
obs.Subscribe(x => Console.WriteLine(x));
也许您可以让我们知道您的基本需求是什么,我们可以对此进行研究?此操作符主要用于冷观测。在订阅新的可观察对象之前,切换取消订阅上一个可观察对象。否则,将存在一种竞赛条件,即额外的赛事可能会在双方都订阅的短暂时间内溜走
因为您的基础可观察是热的,您可能会考虑另一种解决方案,在这里只需修改过滤器/SELECT,而不是使用Switter重新订阅。比如:
source
.Where(t => ApplyCurrentFilter(t))
.Select(t => ApplyCurrentProjection(t))
.Subscribe(...);
// do something that changes what `ApplyCurrentFilter` does...
我不知道这比您当前的解决方案好还是坏,但它确实避免了从源数据取消订阅/重新订阅的需要。如前所述,Observable.Create生成一个cold Observable,Publish.RefCount只会在仍有订户的情况下使其变热。在处理旧的订阅服务器之前,可以编写订阅新订阅服务器的交换机的您自己的版本。但我会对比赛条件非常谨慎。总的来说,这样做感觉有点奇怪,在Rx中通常表示有另一种方式可以做你想做的事情,更干净 在本例中,如果您获得了所需的结果,那么发布多个可观察对象并切换它们是没有意义的,因为实际上您只希望在整个持续时间内订阅一个可观察对象。因此,它如何归结为什么谜说 然而,很明显,这是一个人为的例子,所以让我们假设有一个更复杂的情况需要这种方法——如果您能够详细说明,它可能会有所帮助。从这个例子来看,似乎你只想订阅一次,永远的内在可观察性。基于这一要求,RefCount是不合适的,但我假设您使用它是因为您希望在核心处有一个共享的可观察对象,您正在与其他操作符包装,您希望每次都采取不同的操作。如果是这种情况,您可以使用如下方法:
var obs = Observable.Create<IObservable<int>>(sub =>
{
var item = Observable.Create<int>(innersub =>
{
var count = 0;
return Observable.Interval(TimeSpan.FromSeconds(2))
.Subscribe(x => innersub.OnNext(count++));
}).Publish();
bool connected = false;
var disposables = new CompositeDisposable();
disposables.Add(Observable.Interval(TimeSpan.FromSeconds(10))
.Subscribe(x =>
{
// push the new stream to the observer first
sub.OnNext(item);
if (!connected)
{
connected = true;
disposables.Add(item.Connect());
}
}));
return disposables;
});
我还没有考虑过这种方法的潜在比赛条件等,这在很大程度上取决于你的实际情况。然而,在原始帖子的基本测试中,这似乎是您想要的
var obs = Observable.Create<IObservable<int>>(sub =>
{
var item = Observable.Create<int>(innersub =>
{
var count = 0;
return Observable.Interval(TimeSpan.FromSeconds(2))
.Subscribe(x => innersub.OnNext(count++));
}).Publish();
bool connected = false;
var disposables = new CompositeDisposable();
disposables.Add(Observable.Interval(TimeSpan.FromSeconds(10))
.Subscribe(x =>
{
// push the new stream to the observer first
sub.OnNext(item);
if (!connected)
{
connected = true;
disposables.Add(item.Connect());
}
}));
return disposables;
});