我已经生成/测试了两个Observable来组合执行单个查询。
用户可以拥有多个角色。只要他们的角色id发生变化,就需要更新数据。但是,只有在查询处于活动状态时才会更新数据(当前有一些控件需要数据)。
当暂停查询时,也可能发生角色ID更改。当查询再次变为活动状态时,数据也应加载。
//Tuple has the Id of the current Role and the time that the Id updated
IObservable<Tuple<Guid, DateTime>> idUpdate
//Tuple has the state of the query (true=active or false=suspended)
//and the time the state of the query updated
IObservable<Tuple<bool, DateTime>> queryStateUpdate
我想创建
//A hot observable that pushes true whenever the query should execute
IObservable<bool> execute
我将其分解为两个可以合并的案例,但我无法弄清楚如何创建案例observable。
我已经浏览了视频,lee campbells网站,初学者TOC等,但我似乎找不到这个rx加入的好例子。关于如何创建执行或案例可观察的任何想法?
答案 0 :(得分:1)
鉴于所描述的问题 - 由于我没有看到实际的id(Guid
)用于什么,也没有DateTime
值,这有点模糊 - 我得到了以下内容查询似乎可以解决您的问题:
IObservable<bool> execute =
idUpdate
.Publish(_idUpdate =>
from qsu in queryStateUpdate
select qsu.Item1
? _idUpdate.Select(x => true)
: Observable.Empty<bool>())
.Switch();
我已使用以下idUpdate
&amp; queryStateUpdate
可观察物。
var rnd = new Random();
IObservable<Tuple<Guid, DateTime>> idUpdate =
Observable
.Generate(
0,
n => n < 10000,
n => n + 1,
n => Tuple.Create(Guid.NewGuid(), DateTime.Now),
n => TimeSpan.FromSeconds(rnd.NextDouble() * 0.1));
IObservable<Tuple<bool, DateTime>> queryStateUpdate =
Observable
.Generate(
0,
n => n < 100,
n => n + 1,
n => n % 2 == 0,
n => TimeSpan.FromSeconds(rnd.NextDouble() * 2.0))
.StartWith(true)
.DistinctUntilChanged()
.Select(b => Tuple.Create(b, DateTime.Now));
如果您能就问题提供一些说明,我可能会提供更好的答案以满足您的需求。
编辑:添加了Id在非活动时更改时所需的“重放(1)”行为。
请注意,我已经摆脱了使用DateTime
元组的需要。
IObservable<Guid> idUpdate = ...
IObservable<bool> queryStateUpdate = ...
var replay = new ReplaySubject<Guid>(1);
var disposer = new SerialDisposable();
Func<bool, IObservable<bool>, IObservable<Guid>,
IObservable<Guid>> getSwitch = (qsu, qsus, iu) =>
{
if (qsu)
{
return replay.Merge(iu);
}
else
{
replay.Dispose();
replay = new ReplaySubject<Guid>(1);
disposer.Disposable = iu.TakeUntil(qsus).Subscribe(replay);
return Observable.Empty<Guid>();
}
};
var query =
queryStateUpdate
.DistinctUntilChanged()
.Publish(qsus =>
idUpdate
.Publish(ius =>
qsus
.Select(qsu =>
getSwitch(qsu, qsus, ius))))
.Switch();
答案 1 :(得分:1)
我在阅读问题时说,有一个通知流idUpdate
,只要设置了queryStateUpdate
,就会对其进行处理。如果未设置queryStateUpdate
,则通知应暂停,直到再次设置queryStateUpdate
为止。
在这种情况下,join运算符不会解决您的问题。
我建议您在queryStateUpdate
未设置时需要某种形式的缓存,即
List<Tuple<Guid,DateTime>> cache = new List<Tuple<Guid,DateTime>>();
Subject<Tuple<Guid,DateTime>> execute = new Subject<Tuple<Guid,DateTime>>();
idUpdate.Subscribe( x => {
if (queryStateUpdate.Last().Item1) //might be missing something here with Last, you might need to copy the state out
exeucte.OnNext(x);
else
cache.Add(x);
});
queryStateUpdate.Subscribe(x=> {
if (x.Item1)
{
//needs threadsafety
foreach(var x in cache)
execute.OnNext(x);
cache.Clear();
});
答案 2 :(得分:0)
感谢Enigmativity和AlSki。使用缓存我想出了答案。
var execute = new Subject<Guid>();
var cache = new Stack<Guid>();
idUpdate.CombineLatest(queryStateUpdate, (id, qs) => new { id, qs }).Subscribe( anon =>
{
var id = anon.id;
var queryState = anon.qs;
//The roleId updated after the queryState updated
if (id.Item2 > queryState.Item2)
{
//If the queryState is active, call execute
if (observationState.Item1)
{
cache.Clear();
execute.OnNext(roleId.Item1);
return;
}
//If the id updated and the state is suspended, cache it
cache.Push(id.Item1);
}
//The queryState updated after the roleId
else if (queryState.Item2 > roleId.Item2)
{
//If the queryState is active and a roleId update has been cached, call execute
if (queryState.Item1 && cache.Count > 0)
{
execute.OnNext(cache.Pop());
cache.Clear();
}
}});