.Net(C#)中的反应性扩展-Subject <T>实例仅处理一个订阅

时间:2019-09-09 12:01:58

标签: c# observable reactive-programming system.reactive observers

所以我希望我的标题足够准确,但是我现在非常处于“看不见树木的状态”。

一段时间以来,我一直在研究C#的反应式扩展,直到现在它的表现直观而奇妙,然后我遇到了一个问题:

我创建了一个主题 我创建一个值Observable.Create并调用Subscribe 该值然后愉快地弹出我的OnNext() lambda,万岁!

但是,如果我创建后续的Observable.Return和订阅...,则不会发生任何事情,并且主题包含HasObservers: false

我整理了一个演示该问题的最小控制台片段

    using System.Reactive.Linq;
    using System.Reactive.Subjects;

    static void Main(string[] args)
    {
        Subject<string> messenger = new Subject<string>();
        messenger.Where(o => o.Length > 0).Subscribe(file => { Console.WriteLine("got file request: " + file); });

        var pathObservable = Observable.Return<string>("File 1");
        pathObservable.Subscribe(messenger);

        var pathObservable2 = Observable.Return<string>("File 2");
        pathObservable2.Subscribe(messenger);

        Console.ReadKey();
    }

结果:

Subject subscription example

注意:在有人问我为什么要像使用两个可观察对象(一个序列可以完成)那样愚蠢地做某事之前,这只是一个例子;实际上,两个单独的可观察的创建调用是独立的,并且受到外部文件请求的启发,在这种情况下,问题在于第一个请求成功,而第二个请求成功。

我尝试使用Observable.Create()代替,并使用单个值调用OnNext,结果相同;有趣的是,在这种情况下,在lambda中有一个断点表明,OnNext正在被调用以用于第二个可观察到的事件,只是没有弹出到主题中

任何有关我错过或误解的想法都非常受欢迎, 预先感谢

2 个答案:

答案 0 :(得分:2)

最简单的方法是按照Paulo的建议仅订阅OnNext消息。您还可以从可观察对象中删除或隐藏OnCompleted条消息。

但是,最好的方法是替换messenger主题。我不知道您的用例较大,但是一个很好的目标是尽量减少使用Subject。它们非常适合学习,对于应用程序来说很糟糕。

在这种情况下,您可以用单行代码替换整个代码:

Observable.Merge(
        Observable.Return<string>("File 1"),
        Observable.Return<string>("File 2")
    )
    .Where(o => o.Length > 0)
    .Subscribe(file => Console.WriteLine("got file request: " + file));

如果要模拟动态添加可观察对象,则可能需要使用Subject<IObservable<string>>

Subject<IObservable<string>> consoleWriter = new Subject<IObservable<string>>();
consoleWriter
    .Merge()
    .Where(o => o.Length > 0)
    .Subscribe(file => Console.WriteLine("got file request: " + file));

var pathObservable = Observable.Return<string>("File 1");
consoleWriter.OnNext(pathObservable);

var pathObservable2 = Observable.Return<string>("File 2");
consoleWriter.OnNext(pathObservable2);

答案 1 :(得分:0)

通过让messenger订阅另一个可观察对象,您将使它订阅OnNextOnErrorOnCompleted

如果您在创建Subject<string>之后添加此代码,则会发现它已完成:

messenger.Subscribe(_ => {}, e => Console.WriteLine(e), () => Console.WriteLine("Completed"));

相反,如果您仅添加一个后续操作,则该主题将不会完成:

Subject<string> messenger = new Subject<string>();
messenger.Where(o => o.Length > 0).Subscribe(file => { Console.WriteLine("got file request: " + file); });

var pathObservable = Observable.Return<string>("File 1");
pathObservable.Subscribe(v => messenger.OnNext(v));

var pathObservable2 = Observable.Return<string>("File 2");
pathObservable2.Subscribe(v => messenger.OnNext(v));

messenger.OnNext("File 3");

Console.ReadLine();

输出:

got file request: File 1
got file request: File 2
got file request: File 3