为什么我不应该实现IObservable <t>?</t>

时间:2012-05-07 10:33:50

标签: c# system.reactive

阅读msdn关于Reactive Extensions等等,我发现了一条建议说我不应该实现IObservable,而是使用Observable.Create ......当我读到这篇文章时,我的项目已经有{{ 1}}类,我用它作为IObservable源,我想把事件转换成Observables。

我已经阅读了System.Reactive中的ObservableImplementation<T>实现,但我发现他们的代码和我的代码之间没有任何重大差异。那么实现IObservable有什么问题?我可以添加自己的属性,依此类推......

为了丰满起见,这是我的实施,请告诉我,如果我做错了什么!

AbstractObservable<T>

3 个答案:

答案 0 :(得分:22)

我们不建议人们实施IObservable&lt; T&gt;的原因有几个。直接

一个是缺乏对违反观察者语法的保护。例如,您的序列可能会在OnCompleted调用后显示OnNext调用的行为,该调用无效。 Observable.Create&lt; T&gt;方法和ObservableBase&lt; T&gt;基类型通过在接收到终端消息时自动分离观察者来处理这个问题。因此,即使你的代码做错了事,观察者也看不到错误的序列。

顺便说一句,这与C#中的迭代器类似。实现IEnumerable&lt; T&gt;手动应该是这样当枚举器的MoveNext返回false(类似于OnCompleted)时,后续调用不会改变主意并开始返回true(类似于OnNext):

  

如果MoveNext传递集合的末尾,则枚举数位于集合中的最后一个元素之后,MoveNext返回false。当枚举器处于此位置时,后续对MoveNext的调用也会返回false,直到调用Reset。 (来源:MSDN)

在C#2.0或VB 11.0中使用迭代器时,会为您解决此类问题。这类似于我们的Observable.Create&lt; T&gt;方法和ObservableBase&lt; T&gt;基础类型。

与上述讨论相关的原因是清理。从订阅上的Dispose调用返回后,观察者是否会再看不到任何消息?在向观察者发送终端消息后,是否会自动调用相关订阅的Dispose逻辑?两者都是非常重要的,所以我们的基础实现会解决这个问题。

另一个原因与我们的CurrentThreadScheduler有关,确保在调度程序上运行时,Subscribe调用可以是异步的。基本上,我们需要检查在调用Subscribe期间是否需要在当前线程上安装trampoline。我们不希望每个人都知道这一点并做正确的事。

在你的特殊情况下 - 正如其他人所注意到的那样 - 你正在建立一个非常重要的主题。要么只是使用我们的一个主题,要么用你自己的类型包含它(例如,如果你希望发送“观察者”一方可以被接收“可观察”方面的其他方访问。)

答案 1 :(得分:9)

你不应该实现IObservable<T>的原因与你通常不实现IEnumerable<T>的原因相同,是因为有人很可能已经构建了你想要的东西。在这种情况下,您基本上已经重新实现了Subject<T>

编辑:关于评论中的懒惰问题,我会这样实现:

var lazyObservable = Observable.Create<TFoo>(subj => { /*TODO: Implement Me to load from reflection*/ })
    .Multicast(new Subject<TFoo>())   // This means it'll only calc once
    .RefCount();    // This means it won't get created until someone Subscribes

答案 2 :(得分:6)

来自Rx团队的最近blog post包含三个原因。因为这是一篇冗长的帖子,所以我复制了相关部分。

执行合同

  

Observable.Create接受将成为核心的单个委托   在生成的IObservable上实现Subscribe方法   实现。我们围绕这个代表做了一些巧妙的包装   执行观察员合同,以及其他事情(这就是你的原因   不应该自己实现界面。)

一次性包装

  

返回的一次性物品周围有一个小包装,用于确保   从Dispose返回后,观察者不再被调用   呼叫,即使调度程序可能不是一个好的停止点   然而。 (你应该永远不要实现IObservable的另一个原因   手工界面。哦,顺便说一句,还有更多!)

完成后自动处理

  

这里的兴趣点是应用的自动处置行为   发送OnCompleted下游时的源订阅。   (这是手动实施的另一个原因   强烈建议不要使用IObservable。使用时   Observable.Create,我们会为您解决这个问题。)