这是一个学术练习,我是Reactive Extensions的新手,并试图了解技术。我为自己设定了一个目标,即创建一个返回Pi的连续数字的IObservable(由于无关的原因,我恰好对Pi目前非常感兴趣)。 Reactive Extensions包含用于制作可观察对象的运算符,它们给出的指导是“几乎不需要创建自己的IObsevable”。但我看不出如何用现成的操作符和方法来做到这一点。让我进一步阐明一下。
我计划使用an algorithm,这将涉及为Arctan扩展泰勒系列。为了获得Pi的下一个数字,我将在该系列中扩展一些术语。
所以我需要异步进行系列扩展,偶尔会将下一个计算数字丢弃到IObserver。我显然不希望从头开始为每个新数字重新开始计算。
有没有办法使用RX的内置运算符来实现这种行为,或者我将不得不从头开始编写IObservable代码?什么策略表明自己?
答案 0 :(得分:2)
对于这样的事情,最简单的方法是使用Subject。 Subject既是IObservable又是IObserver,听起来有点奇怪,但它可以让你像这样使用它们:
class PiCalculator
{
private readonly Subject<int> resultStream = new Subject<int>();
public IObservable<int> ResultStream
{
get { return resultStream; }
}
public void Start()
{
// Whatever the algorithm actually is
for (int i = 0; i < 1000; i++)
{
resultStream.OnNext(i);
}
}
}
因此,在您的算法中,只要您想要生成下一个值,就可以在主题上调用OnNext
。
然后使用它,你只需要:
var piCalculator = new PiCalculator();
piCalculator.ResultStream.Subscribe(n => Console.WriteLine((n)));
piCalculator.Start();
答案 1 :(得分:1)
最简单的方法是创建Enumerable
然后转换它:
IEnumerable<int> Pi()
{
// algorithm here
for (int i = 0; i < 1000; i++)
{
yield return i;
}
}
用法(对于冷可观察,即每个新的'订阅'开始从头开始创建Pi):
var cold = Pi().ToObservable(Scheduler.ThreadPool);
cold.Take(5).Subscribe(Console.WriteLine);
如果你想让它hot
(每个人共享相同的基础计算),你可以这样做:
var hot = cold.Publish().RefCount();
将在第一个订户之后开始计算,并在它们全部断开连接时停止计算。这是一个简单的测试:
hot.Subscribe(p => Console.WriteLine("hot1: " + p));
Thread.Sleep(5);
hot.Subscribe(p => Console.WriteLine("hot2: " + p));
哪个应该只显示hot1
打印一段时间,然后hot2
在短暂的等待后加入,但打印相同的数字。如果使用cold
完成此操作,则两个订阅将从0开始。