问题
I need to ignore Observable values for a period of time when another Observable provides a value.
Currently, my implementation uses a variable to control blocking (or ignoring).
bool block = false;
var blocker = observable1.Do(_ => block = true )
.Throttle( _ => Observable.Timer(_timeToBlock)
.Subscribe( _ => block = false ));
var receiver = observable2.Where( i => !block && SomeCondition(i) )
.Subscribe( i=> EvenMoreStuff(i) );
Is there a more Rx way to do this, by combining these two observables?
EDIT: small change to blocker subscription
回答1:
The first task is to express your block
variables as an observable.
IObservable<bool> blockObservable = observable1
.Select(x => Observable.Concat(
Observable.Return(true),
Observable.Return(false).Delay(_timeToBlock)))
.Switch()
.DistinctUntilChanged();
Each time observable1
emits a value, we select an observable that emits true
, waits _timeToBlock
, then emits false
. The Switch
just always switches to the most recent of those observables.
Here's a marble diagram. Let's assume that _timeToBlock
is 3 characters long.
observable1 -----x--xx-x-----x-----
select0 T--F
select1 T--F
select2 T--F
select3 T--F
select4 T--F
switch -----T--TT-T--F--T--F--
blockObservable -----T--------F--T--F--
Now we can Zip
your sequence of values with the MostRecent
value of the blockObservable
.
var receiverObservable = observable2
.Zip(blockObservable.MostRecent(false), (value, block) => new { value, block })
.Where(x => !x.block)
.Select(x => x.value);
回答2:
As an alternative using disposables you could create a small extension method:
public static IObservable<TResult> Suppress<TResult, TOther>(
this IObservable<TResult> source,
IObservable<TOther> other,
TimeSpan delayFor)
{
return Observable.Create<TResult>(observer => {
var published = source.Publish();
var connected = new SerialDisposable();
Func<IDisposable> connect = () => published.Subscribe(observer);
var suppressor = other.Select(_ => Observable.Timer(delayFor)
.Select(_2 => connect())
.StartWith(Disposable.Empty))
.Switch();
return new CompositeDisposable(
connected,
suppressor.StartWith(connect())
.Subscribe(d => connected.Disposable = d),
published.Connect());
});
}
This will convert the source observable into a ConnectableObservable
, then every time the other
source emits it will dispose of its subscription, then reconnect when the timer expires.
来源:https://stackoverflow.com/questions/31025784/momentarily-ignore-values-from-observable-when-another-observable-provides-a-val