这是以下问题:Infinite IObservable from Task function and toggle observable
以上问题询问是否可以从IObservable<TResult>
和IObservable<bool> toggle
创建重复的Task<TResult> query
,以便在最后toggle
为true
时重复调用该查询如果上一个toggle
是false
,则根本不会被调用。使用Defer
和Switch
方法似乎很容易实现这一点。
但这有问题,因为查询没有参数化。具体地说,query
函数有两种类型的参数(使签名Func<int, TParam, IQueryable<TResult>>
)。每次调用方法时,第一个参数都会递增。第二个参数是另一个IObservable<TParam> params
的最新值。
同样,我希望能够自动测试此设置。
这是方法树桩:
public static IObservable<TResult> Function<TParam, TResult>(IObservable<bool> toggle, IObservable<TParam> param, Func<int, TParam, IObservable<TResult>> query)
{
param.Subscribe(a => { }); // dummy to make debug output
return toggle
.Select(b => b
? Observable
.Defer(() => query(0, default(TParam))) // dummy parameters for debugging
.Repeat()
: Observable
.Never<TResult>())
.Switch();
}
测试应该通过:
[Test]
public void Test_Function()
{
var scheduler = new TestScheduler();
var toggle = scheduler.CreateHotObservable(
OnNext(10, false),
OnNext(11, true),
OnNext(18, false),
OnNext(30, true),
OnNext(45, false),
OnNext(100, false)
).Do(x => Console.WriteLine(scheduler.Clock + " toggle " + x));
var prms = scheduler.CreateHotObservable(
OnNext(10, "a"),
OnNext(29, "b"),
OnNext(39, "c")
).Do(x => Console.WriteLine(scheduler.Clock + " param " + x));
var resultObs =
Function(toggle, prms, (p1, p2) => scheduler.CreateColdObservable(OnNext(2, p1 + " " + p2), OnCompleted<string>(2)))
.Do(x => Console.WriteLine(scheduler.Clock + " " + x));
var results = scheduler.Start(() => resultObs, 0, 0, 100);
results.Messages.AssertEqual(
//10 toggle False
//10 param a
//11 toggle True
OnNext(13, "0 a"),
OnNext(15, "1 a"),
OnNext(17, "2 a"),
//18 toggle False // should not continue after toggle is off
//29 param b
//30 toggle True
OnNext(32, "0 b"),
OnNext(34, "1 b"),
OnNext(36, "2 b"),
OnNext(38, "3 b"),
//39 param c
OnNext(40, "4 b"), // fine if on parameter change, the currently running query finishes
OnNext(42, "5 c"),
OnNext(44, "6 c")
//45 toggle False
//100 toggle False
);
}
答案 0 :(得分:0)
所以我想到了更多,并设法找到了一个有效的解决方案。
public class Function2
{
private readonly IObservable<bool> _toggle;
private readonly IObservable<string> _param;
private readonly Func<int, string, IObservable<string>> _query;
private int _index;
private string _latestParam;
public Function2(IObservable<bool> toggle, IObservable<string> param, Func<int, string, IObservable<string>> query)
{
_toggle = toggle;
_param = param;
_query = query;
}
public IObservable<string> Execute()
{
// TODO : Dispose the subscriptions
_toggle.Subscribe(OnToggle);
_param.Subscribe(OnParam);
return _toggle
.Select(b => b
? Observable
.Defer(InnerQuery)
.Repeat()
: Observable
.Never<string>())
.Switch();
}
private void OnToggle(bool tgl)
{
// if toggle is on, reset the index
if(tgl)
{
_index = 0;
}
}
private void OnParam(string param)
{
_latestParam = param;
}
private IObservable<string> InnerQuery()
{
var ret = _query(_index, _latestParam);
_index++;
return ret;
}
}
但我不喜欢它,因为:
index
。这看起来像是带有副作用的坏话。toggle
需要订阅两次我喜欢它,因为它可以根据传入的参数更改和更新索引,轻松微调和修改参数更新的行为。