我想使用一个可以随时填充的IObservable。
我有这种扩展方法:
public static IObservable<TOut> Drain<TSource, TOut>(this IObservable<TSource> source,
Func<TSource, IObservable<TOut>> selector)
{
return Observable.Defer(() =>
{
BehaviorSubject<Unit> queue = new BehaviorSubject<Unit>(new Unit());
return source
.Zip(queue, (v, q) => v)
.SelectMany(v => selector(v)
.Do(_ =>
{
}, () =>
{
queue.OnNext(new Unit());
})
);
});
}
我使用如下:
_moviesToTranslateObservable = new Subject<IMovie>();
_moviesToTranslateObservable.Drain(s => Observable.Return(s).Delay(TimeSpan.FromMilliseconds(250)))
.Subscribe(async movieToTranslate =>
{
}
一旦按下新项目:
_moviesToTranslateObservable.OnNext(movieToTranslate);
使用IObservable。
我的问题是,当我添加很多项目时,我想要的不是第一个添加的项目,而是最后添加的项目(如堆栈,而不是队列)。
我怎样才能做到这一点? BehaviorSubject是否适合堆栈消费行为?
答案 0 :(得分:2)
我知道变量名称是queue
,但BehaviorSubject
实际上并不是一个队列,它更像是一个锁。排队确实发生在Zip
函数内,该函数带有内部队列。
就FIFO和LIFO之间的切换而言,我不确定你想要什么标准,但这里是Drain
的FIFO版本。
public static IObservable<TOut> DrainReverse<TSource, TOut>(this IObservable<TSource> source,
Func<TSource, IObservable<TOut>> selector)
{
return Observable.Defer(() =>
{
BehaviorSubject<Unit> queue = new BehaviorSubject<Unit>(new Unit());
var stack = new Stack<TSource>();
return source
.Do(item => stack.Push(item))
.Zip(queue, (v, q) => v)
.Select(_ => stack.Pop())
.SelectMany(v => selector(v)
.Do(_ =>
{
}, () =>
{
queue.OnNext(new Unit());
})
);
});
}
与以下运行代码一起使用时:
var s = new Subject<int>();
var d = s.DrainReverse(i => Observable.Return(i).Delay(TimeSpan.FromMilliseconds(250)));
d.Subscribe(i => Console.WriteLine(i));
s.OnNext(0);
s.OnNext(1);
s.OnNext(2);
s.OnNext(3);
s.OnNext(4);
s.OnNext(5);
哪个正确地产生0, 5, 4, 3, 2, 1