我正在学习.NET中的反应式扩展(rx),并且在“预订”的真正含义和使用时间方面有些挣扎。
让我们从this线程中获取一些样本数据:
using System;
using System.Reactive.Linq;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
class Result
{
public bool Flag { get; set; }
public string Text { get; set; }
}
static void Main(string[] args)
{
var source =
Observable.Create<Result>(f =>
{
Console.WriteLine("Start creating data!");
f.OnNext(new Result() { Text = "one", Flag = false });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "two", Flag = true });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "three", Flag = false });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "four", Flag = false });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "five", Flag = true });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "six", Flag = true });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "seven", Flag = true });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "eight", Flag = false });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "nine", Flag = true });
Thread.Sleep(1000);
f.OnNext(new Result() { Text = "ten", Flag = false });
return () => Console.WriteLine("Observer has unsubscribed");
});
}
}
}
当心这一行:
Console.WriteLine("Start creating data!");
现在,首先,我认为只需使用.Subscribe
运算符即可使用订阅。因此,观察者(例如.Subscribe
函数的回调)订阅了这样的可观察对象(操作符链的最后一个返回值)(仅作为示例,查询没有实际用途):
source.Zip(source, (s1, s0) =>
s0.Flag
? Observable.Return(s1)
: Observable.Empty<Result>()).Merge().Subscribe(f => { Console.WriteLine(f.Text); });
现在我期望得到“开始创建数据!”仅输出一次,因为我只使用一个订阅。但实际上,我两次获得了:
Start creating data!
Start creating data!
two
five
six
seven
nine
有人告诉我,每次在source.
上使用运算符时,都会进行订阅。但是在此示例中,我仅使用source.
一次,然后再次使用.Zip
作为操作符的参数。还是因为通过再次订阅的值将源传递到.Zip
函数?
所以我的问题是:
顺便说一句。我知道我可以使用.Publish
运算符来防止发生多个订阅,但这不是我的问题的范围。
答案 0 :(得分:2)
简单来说,“订阅”仅代表已订阅的Observable
。可以通过使用.Subscribe
显式地进行此过程,也可以通过加入两个或多个Observables
并随后订阅所生成的链来隐式地进行该过程。
在您的情况下,您会看到两种情况都发生,一次是在调用Subscribe
时显式发生,一次是在将source
传递到Zip
时隐性发生,即有两个{{1} }到Subscriptions
source
。
为什么那么重要?因为默认情况下Observable
是惰性的,这意味着它们只有在您订阅它们后才会开始处理(该过程的产品为Observables
),从广义上讲,这意味着 any 订阅Subscription
时,它将有效地开始新的视频流。可以像您用Observable
所提到的那样来覆盖此行为,但是默认情况下,每个Publish
都要 cold 。
在您的特定情况下,由于您要将相同的Observable
传递给Observable
,因此需要订阅两次,因为它将把来自两个传递的流的事件压缩在一起。结果是对同一Zip
的两个订阅,每个订阅彼此独立运行。