当我需要SelectMany observables时,我是否以正确的方式思考?

时间:2017-04-13 14:10:39

标签: c# system.reactive

所以我可能最终会对以下代码提出几个问题,可能是因为我使用的是Subject,我不确定它是否可以使用。

我很难解释,我不知道为什么,也许我缺乏术语。

我想要做的是有一种可以用它注册几个observable的类型,所以我可以传递这个类型并将所有的observable分组并从中公开一个observable。

所以我的第一个问题我感觉我没有以正确的方式思考问题,我想知道这是否正确还是有更多的反应性问题。这样做的方式?

我的意思是我有这种类型你可以注册observables,同样的类型也会暴露我也可以订阅的单个Observable。

我将尝试使用下面的代码示例解释一下。 因此,SomeTypeWithObservable可能是会暴露IObservable<SomeEvents>的众多类型之一 ReactiveTesting类型是尝试将所有可观察对象组合在一起并公开单个IObservable<SomEvents>的类型。有RegisterObservable方法将其发送到内部Subject<IObservable<SomeEvents>>。构造函数将我想要公开的Observable设置为此主题的SelectMany

使用下面的实现,在ReactiveTesting构造函数中执行SelectMany.Publish.RefCount,然后使用虚拟订阅启动observable,我注意到如果我没有使用虚拟订阅注册没有使用可观察物。

所以我的第二个问题是代码可以有一个虚拟订阅来启动observable,或者我应该做我在评论中做了什么,我只是从Publish可以连接,然后之后立即连接它,或者它们都是错误的,在这种情况下,有人能指出我正确的方向吗?

我的第三个问题我应该使用某个主题吗?

如果我在订阅之前致电RegisterObservable,如果我没有将虚拟Subscribe放入或Connect,那么我就不会观察任何一个触发事件。

我的第四个问题有人可以解释后者吗? 我有点想,因为它是PublishRefCount,所以在有一个从Observable开始的订阅之前没有什么可做的。

代码

- 已修改 - 要显示我想在ReactiveTesting

中注册多个观察点
enum SomeEvents
{
    event1,
    event2,
    event3,
    event4
}

interface ISomeTypeWithObservable
{
    IObservable<SomeEvents> SomeObservableEvents { get; }
}

class SomeTypeWithObservable2 : ISomeTypeWithObservable
{
    private event EventHandler SpecialEvent;
    public SomeTypeWithObservable2()
    {
        var observableFromSpecialEvent = Observable.FromEventPattern(h => SpecialEvent += h, h => SpecialEvent -= h).Select(x => SomeEvents.event2);
        SomeObservableEvents = Observable.Create<SomeEvents>(observer =>
            {
                return observableFromSpecialEvent.Subscribe(observer);
            })
            .Publish()
            .RefCount();
    }

    public IObservable<SomeEvents> SomeObservableEvents { get; }
    public void TriggerEvent()
    {
        SpecialEvent.Invoke(this, new EventArgs());
    }
}

class SomeTypeWithObservable : ISomeTypeWithObservable
{
    private event EventHandler SpecialEvent;
    public SomeTypeWithObservable()
    {
        var observableFromSpecialEvent = Observable.FromEventPattern(h => SpecialEvent += h, h => SpecialEvent -= h).Select(x => SomeEvents.event1);
        SomeObservableEvents = Observable.Create<SomeEvents>(observer =>
            {
                return observableFromSpecialEvent.Subscribe(observer);
            })
        .Publish()
        .RefCount();
    }

    //Some code in here that will produce things to observe, maybe Observable.FromEventPattern...
    public IObservable<SomeEvents> SomeObservableEvents { get; }

    public void TriggerEvent()
    {
        SpecialEvent.Invoke(this, new EventArgs());
    }
}

class ReactiveTesting
{
    private Subject<IObservable<SomeEvents>> _innerEvents = new Subject<IObservable<SomeEvents>>();

    public IObservable<SomeEvents> AllEvents;
    public ReactiveTesting()
    {
        AllEvents = _innerEvents.SelectMany(x => x).Publish().RefCount();
        AllEvents.Subscribe(next => { }, exception => { }, () => { });

        //This instead of the above??
        //var connectableObservable = _innerEvents.SelectMany(x => x).Publish();
        //AllEvents = connectableObservable;
        //connectableObservable.Connect();
    }

    public void RegisterObservable(ISomeTypeWithObservable someTypeWithObservable)
    {
        _innerEvents.OnNext(someTypeWithObservable.SomeObservableEvents);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var reactiveTesting = new ReactiveTesting();
        var someTypeWithObservable = new SomeTypeWithObservable();
        var someTypeWithObservable2 = new SomeTypeWithObservable2();
        reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 1 - {0}", next.ToString("G"))));
        reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 2 - {0}", next.ToString("G"))));
        reactiveTesting.RegisterObservable(someTypeWithObservable);
        reactiveTesting.RegisterObservable(someTypeWithObservable2);
        someTypeWithObservable.TriggerEvent();
        someTypeWithObservable.TriggerEvent();
        someTypeWithObservable.TriggerEvent();
        someTypeWithObservable2.TriggerEvent();
        someTypeWithObservable2.TriggerEvent();
        someTypeWithObservable2.TriggerEvent();

        Console.WriteLine("Press key...");
        Console.ReadLine();
    }
}

1 个答案:

答案 0 :(得分:0)

  

所以我的第一个问题是我感觉我没有考虑过的事情   正确的方法,我想知道这是否正确或有更多   &#34;反应&#34;这样做的方式?

Subject中使用ReactiveTesting通常是一个提示,您可以使用一些必要的代码来消除或推进。它可能需要重写一些您周围的代码。在这种情况下,你最终会得到这样的东西:

class ReactiveTesting
{
    public IObservable<SomeEvents> AllEvents { get; }
    public ReactiveTesting(IObservable<IObservable<SomeEvents>> eventSource)
    {
        AllEvents = eventSource.Merge().Publish().RefCount();
    }
}
class Program
{
    public static void Main(string[] args)
    {
        var someTypeWithObservable = new SomeTypeWithObservable();
        var reactiveTesting = new ReactiveTesting(Observable.Return(someTypeWithObservable.SomeObservableEvents));
        reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 1 - {0}", next.ToString("G"))));
        reactiveTesting.AllEvents.Subscribe(next => Console.WriteLine(string.Format("Subscriber 2 - {0}", next.ToString("G"))));
        someTypeWithObservable.TriggerEvent();
        someTypeWithObservable.TriggerEvent();
        someTypeWithObservable.TriggerEvent();

        Console.WriteLine("Press key...");
        Console.ReadLine();

    }
}
  

所以我的第二个问题是代码可以进行虚拟订阅   从观察开始,或者我应该做我在下面做的事情   评论我刚刚发布了一个可连接的发布然后连接   它紧接着它,或者它们都是错的,在那种情况下,它可以   有人指出我正确的方向?

没有必要。它对我来说就像删除它一样。虚拟订阅有助于.Replay().Refcount()。我没有看到.Publish()的重点。

  

我的第三个问题我应该使用某个主题吗?

他们基本上是代码味道。如果你可以消除它们,或者将它们从业务逻辑中推开,那么你就会更好。