C# 可观测范围是否打破了可观测合同?

C# 可观测范围是否打破了可观测合同?,c#,system.reactive,reactive-programming,observable,reactive,C#,System.reactive,Reactive Programming,Observable,Reactive,在学习Rx的过程中,我遇到了一条关于观测值的经常重复的规则,这条规则在 发出未完成或错误通知后,不得再发出任何通知 这对我来说很有意义,因为让一个可观察对象在完成后继续产生值会让人困惑,但当我在.NET中测试Observable.Range方法时,我注意到它没有表现出这种行为,事实上许多可观察对象违反了这条规则 var rangeObservable = Observable.Range(0, 5); rangeObservable.Subscribe(Console.WriteLine, (

在学习Rx的过程中,我遇到了一条关于观测值的经常重复的规则,这条规则在

发出未完成或错误通知后,不得再发出任何通知

这对我来说很有意义,因为让一个可观察对象在完成后继续产生值会让人困惑,但当我在.NET中测试Observable.Range方法时,我注意到它没有表现出这种行为,事实上许多可观察对象违反了这条规则

var rangeObservable = Observable.Range(0, 5);

rangeObservable.Subscribe(Console.WriteLine, () => Console.WriteLine("Done first!"));
Console.ReadLine();

rangeObservable.Subscribe(Console.WriteLine, () => Console.WriteLine("Done second!"));
Console.ReadLine();

//Output:
//0
//1
//2
//3
//4
//Done first!

//0
//1
//2
//3
//4
//Done second!
显然,
rangeObservable
调用了两次
OnComplete
,并在第一次
OnComplete
之后生成了值。这让我相信,这不是一条关于可观测的规则,而是一条关于订阅的规则。也就是说,只要每个订阅只接收一条终止消息,并且此后不再接收其他消息,一个可观测对象可能会产生它想要的任意多条终止消息,甚至在它产生之后产生值


当它说“可观察”时,它们实际上是指订阅吗?它们真的不同吗?我是否对模型有一个根本性的误解?

可观察合约必须对任何可观察到的有效。 当可观察到的事物不被观察到时,是否发生了任何事情都要由可观察事物的实现来决定

这有助于将可枚举-可观测中的模拟看作可枚举的对偶。在枚举数中,您将
range=Enumerable.range(0,5)
,您可以使用与上面类似的范围:

range.ForEach(Console.WriteLine); //prints 0 - 4

range.ForEach(Console.WriteLine); //prints 0 - 4 again
并发现这是完全可以接受的行为,因为只有在调用
GetEnumerator
时才会创建实际的数字生成器。类似地,在Observable中,等效方法是
Subscribe

range的实现类似于:

        static IObservable<int> Range(int start, int count)
        {
            return Observable.Create<int>(observer =>
            {
                for (int i = 0; i < count; i++)
                    observer.OnNext(start + i);

                observer.OnCompleted();

                return Disposable.Empty;
            });
        }
静态IObservable范围(int开始,int计数)
{
返回可观察的。创建(观察者=>
{
for(int i=0;i
这里,每次有订阅时都会调用
observer=>{…}
函数。这项工作在subscribe方法中完成。您可以很容易地看到,它(1)为每个观察者推送相同的序列,(2)每个观察者只完成一次

这些只有在你观察时才会发生的观察被称为冷观察。描述概念

注意

范围
是一个非常简单的实现,仅用于说明目的。该方法在完成之前不会返回一次性文件,因此可以接受
disposable.Empty
。正确的实现将在调度程序上运行该工作,并在继续循环之前使用选中的一次性命令查看订阅是否已被释放


值得注意的是,手工实现可观察契约很难,这就是为什么Rx库存在的原因——通过组合构建功能。

observable.Range
返回一个冷可观察,这意味着它“重放”每个订阅者的行为。由于“OnNext*OnComplete | OnError”合同仅适用于订阅,因此完全可以


有关热/冷观测的更多信息,请参见

我想得越多,这个答案就越明显!当我们谈论一些可观察的生产值时,它指的是单个订阅的生产值。我没有想到的情况是,当一个可观察对象有多个观察者时,它会发送大量未完成的消息,尽管是“同时”。由于这是一种常见的情况,可观察的合同永远不会拒绝它。啊!我熟悉冷热观测的概念。我的问题可以用“所有冷的可观测物都打破了可观测的契约吗?”来表达,因为所有这些都与我之前的理解一致。完美。思想上的转变使我能够理解这一点,是认识到一个可观察的不应该被视为一个“对象”,而应该被视为一个“订阅方法”。只是一个每次有东西想要订阅时调用的方法。事实上,如果没有这个模型,我真的不知道如何实现Range操作符。你要做什么,只要让每一个范围操作符在构建完成后立即启动?没有人能从中得到任何价值@哈哈。在钱的问题上。@Asti-除了实现
范围
-如果你发现自己在写
返回一次性的.Empty
.Create
方法中,您做错了什么。@Enigmativity您完全正确。这是一个非常幼稚的实现,只是为了举例说明。但是,该方法在完成之前不会返回一次性的,所以我推断它返回什么并不重要。一个正确的实现将在调度程序上运行该工作,并可能使用一个检查过的一次性文件,但这可能会使解释更加混乱。@Asti-最好将该解释添加到答案中。我讨厌有人在生产代码中使用这个实现。