来自任务功能的无限IObservable和带参数的切换可观察

时间:2016-10-12 08:09:48

标签: c# .net .net-4.5 system.reactive

这是以下问题:Infinite IObservable from Task function and toggle observable

以上问题询问是否可以从IObservable<TResult>IObservable<bool> toggle创建重复的Task<TResult> query,以便在最后toggletrue时重复调用该查询如果上一个togglefalse,则根本不会被调用。使用DeferSwitch方法似乎很容易实现这一点。

但这有问题,因为查询没有参数化。具体地说,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
        );
}

1 个答案:

答案 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需要订阅两次
  • 我不确定是否以及如何处理处理订阅。这将从应用程序的开始到结束运行,因此它可能不是问题,但仍然存在。

我喜欢它,因为它可以根据传入的参数更改和更新索引,轻松微调和修改参数更新的行为。