Recursive / fan-out in Reactive Extensions

前端 未结 1 1981
感动是毒
感动是毒 2021-01-06 05:00

I\'m attempting to piece together a Rx pipeline that works as follows:

  1. I have written a function that takes in an IObservable providing me with profiles contai
相关标签:
1条回答
  • 2021-01-06 05:57

    It sounds like you want a dataflow like this:

    seed profiles --> source --> get related --> output
                         ^                    |
                         |                    v
                         -<--- transform <-----
    

    This seems like a case where solving the general problem is as easy or easier than the specific one, so I'll propose a generic "feedback" function that should give you the building blocks you need:

    edit: fixed function to complete

    IObservable<TResult> Feedback<T, TResult>(this IObservable<T> seed,
                                              Func<T, IObservable<TResult>> produce,
                                              Func<TResult, IObservable<T>> feed)
        {
            return Observable.Create<TResult>(
                    obs =>
                    {
                        var ret = new CompositeDisposable();
                        Action<IDisposable> partComplete = 
                            d =>
                            {
                                ret.Remove(d);
                                if (ret.Count == 0) obs.OnCompleted();
                            };
                        Action<IObservable<T>, Action<T>> ssub =
                            (o, n) =>
                            {
                                var disp = new SingleAssignmentDisposable();
                                ret.Add(disp);
                                disp.Disposable = o.Subscribe(n, obs.OnError, () => partComplete(disp));
                            };
                        Action<IObservable<TResult>, Action<TResult>> rsub =
                            (o, n) =>
                            {
                                var disp = new SingleAssignmentDisposable();
                                ret.Add(disp);
                                disp.Disposable = o.Subscribe(n, obs.OnError, () => partComplete(disp));
                            };
    
                        Action<T> recurse = null;
                        recurse = s =>
                                  {
                                      rsub(produce(s),
                                           r => 
                                           {
                                               obs.OnNext(r);
                                               ssub(feed(r), recurse);
                                           });
                                  };
    
                        ssub(seed, recurse);
                        return ret;
                    });
        }
    

    In your case, T and TResult appear to be the same, so feed will be the identity function. produce will be the functions used to implement step 2 and 3.

    Some sample code I tested this function with:

    void Main()
    {
        var seed = new int[] { 1, 2, 3, 4, 5, 6 };
        var found = new HashSet<int>();
        var mults = seed.ToObservable()
                        .Feedback(i =>
                                  {
                                      return Observable.Range(0, 5)
                                             .Select(r => r * i)
                                             .TakeWhile(v => v < 100)
                                             .Where(v => found.Add(v));
                                  },
                                  i => Observable.Return(i));
    
        using (var disp = mults.Dump())
        {
            Console.WriteLine("Press any key to stop");
            Console.ReadKey();
        }
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
    
    static IDisposable Dump<T>(this IObservable<T> source)
    {
        return source.Subscribe(item => Console.WriteLine(item),
                                ex => Console.WriteLine("Error occurred in dump observable: " + ex.ToString()),
                                () => Console.WriteLine("Dump completed"));
    }
    
    0 讨论(0)
提交回复
热议问题