我正在尝试拼凑一个如下工作的Rx管道:
我使用一些已知的良好配置文件来引导该过程。
最终,没有更多匹配的配置文件尚未显示,因此流程结束。
我在编程时遇到了麻烦。如果我使用Subject来允许管道的尾端将其配置文件发送到工作流的开头,那么没有人会调用OnCompleted并且我从未发现该过程已经结束。如果我用递归来开发它,我似乎总是以堆栈溢出结束,因为我试图用自己的返回值调用一个函数。
任何人都可以帮助我完成这项任务,我可以确定这个过程已经结束了吗?
答案 0 :(得分:7)
听起来你想要一个像这样的数据流:
seed profiles --> source --> get related --> output
^ |
| v
-<--- transform <-----
这似乎是解决一般问题比特定问题容易或容易的情况,因此我将提出一个通用的“反馈”功能,它应该为您提供所需的构建块:
编辑:修复完成的功能
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;
});
}
在您的情况下,T
和TResult
似乎相同,因此feed
将成为身份功能。 produce
将是用于实施步骤2和3的函数。
我测试了这个函数的一些示例代码:
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"));
}