C# 为什么每次订阅都会完全解析IObservable链?

C# 为什么每次订阅都会完全解析IObservable链?,c#,system.reactive,C#,System.reactive,我有一个问题是如何解决爱宝宝链的问题。 我认为,如果多个观察者订阅同一个IObservable,那么如果流发出一个新项,整个链将只解析一次 相反,似乎每个订阅都会运行整个链 如果我的整个程序逻辑都是使用IObservables并将它们链接在一起,那么在我看来,代码运行的方法是相同的,结果也是相同的 这是故意的行为吗?为什么 如果是,可以避免吗?或者这是个坏主意 下面的代码是用LINQPad编写的: { var subject = Observable.Range(1, 1);

我有一个问题是如何解决爱宝宝链的问题。 我认为,如果多个观察者订阅同一个IObservable,那么如果流发出一个新项,整个链将只解析一次

相反,似乎每个订阅都会运行整个链

如果我的整个程序逻辑都是使用IObservables并将它们链接在一起,那么在我看来,代码运行的方法是相同的,结果也是相同的

  • 这是故意的行为吗?为什么

  • 如果是,可以避免吗?或者这是个坏主意

下面的代码是用LINQPad编写的:

{
    var subject = Observable.Range(1, 1);

    var observable1 = subject
        .Select(value =>
        {
            var nextValue = value + 2;
            Console.Write("\n Result of expensive computation: " + nextValue);
            return nextValue;
        });

    var observable2 = observable1
        .Select(value =>
        {
            var nextValue = 2 * value;
            Console.Write("\n Result of another expensive computation: " + nextValue);
            return nextValue;
        });

    observable2.Subscribe(_ => Console.Write("\n Data received on first subscription."));

    observable2.Subscribe(_ => Console.Write("\n Data received on second subscription."));
}
结果:

计算结果:3

另一个昂贵计算的结果:6

第一次订阅时收到的数据

计算结果:3

另一个昂贵计算的结果:6

第二次订阅时收到的数据

然而,我期望:

计算结果:3

另一个昂贵计算的结果:6

第一次订阅时收到的数据

第二次订阅时收到的数据

谢谢你的回答

干杯,
Rob

首先回答您的问题:

  • 是的,这是故意的行为
  • 是的,这是可以避免的
  • 回避不是个坏主意
正如@supertopi所说,您创建了一个冷可观测对象,其功能如您所述。把它变成一个热门的可观察对象,你就会拥有你想要的功能

您可以按如下方式进行操作:

{
    var subject = Observable.Range(1, 1);

    var observable1 = subject
        .Select(value =>
        {
            var nextValue = value + 2;
            Console.Write("\n Result of expensive computation: " + nextValue);
            return nextValue;
        });

    var observable2 = observable1
        .Select(value =>
        {
            var nextValue = 2 * value;
            Console.Write("\n Result of another expensive computation: " + nextValue);
            return nextValue;
        });

    var hotObservable = observable2.Publish().RefCount();

    hotObservable.Subscribe(_ => Console.Write("\n Data received on first subscription."));

    hotObservable.Subscribe(_ => Console.Write("\n Data received on second subscription."));

}
冷观测值:

  • 多个订阅触发链接操作的多个代码重新运行
  • 通常来源于可观察的。创建/范围/生成/间隔/计时器
  • 类似于明确定义项目之间时间间隔的可枚举项目
热观测值:

  • 多个订阅通常共享链接操作的结果
  • 通常来源于事件、已发布的冷可观察事件或
    主题
  • 就像一系列你可以处理的事件;不管你喜欢与否,它们都会发生
在我看来,最好的区别在于源代码是否在没有订阅的情况下“运行”。例如,无论是否有人订阅,按钮点击事件仍然会发生。相反,
Observable.Timer
在没有订阅的情况下不会执行任何操作


至于为什么。。。我不能代表Rx设计师说话。冷态与热态的观测值经常引起混淆/错误。我认为,在他们周围有一个更好的明确性可以改善这种情况。话虽如此,我不确定这是怎么做到的。

这是冷观测的预期行为,可以通过使观测变热来避免。我建议你在Lee Campbell关于Rx的介绍中读一下冷热观测。或者通过SO文档,谢谢,这让我走上了正确的轨道。我真的应该再读几遍那个网站。谢谢。因此.Publish().RefCount()通常用于使冷的可观察到的热。但是,在代码修复中,第二个订阅服务器从不触发。第一个订户让可观察对象运行其创建函数,并在第二个订户可以订阅之前结束它,对吗?正确。因为在任何可观察对象中都没有异步性,所以所有东西都是同步运行的。即使您将源代码增加到
var subject=Observable.Range(100000000)或其他一些大数字,第二个不会发射。所有一百万个数字都将在第一个订阅上同步运行。如果要使用异步值对其进行测试,请使用
var subject=Observable.Timer(TimeSpan.frommissions(10))。选择(=>1)。这将导致两个订阅都被取消。