合并从多个实例激发的事件的可观察序列的正确方法

本文关键字:观察 方法 事件 实例 合并 | 更新日期: 2023-09-27 18:21:07

假设我有一个工厂方法,它可以生成类型为T的实例,并且我希望从工厂方法发出的所有实例中激发的事件都有一个Rx可观察序列。

像我下面所做的那样使用Merge()是实现这一目标的正确和最佳方式吗?

我做这件事的另一种方法是使用静态事件,并从中产生可观察的序列,但我通常不喜欢使用静态事件。我很好奇Rx专家认为在这种情况下什么是最佳的?

public T MakeFoo<T>() where T: Foo, new()
{
    this.instanceOfObservable.Merge(new T());
    return self;
}

public class ObservableSequence : IObservable<EventArgs>, IDisposable
{
    private IObservable<EventArgs> stream;
    public ObservableSequence()
    {
    }
    // this method is called in the factory method for each new instance of T
    public void Merge(Foo instance)
    {
        if (this.stream == null)
        {
            this.stream = Init(instance); 
        }
        else
        {
            IObservable<EventArgs> next = Init(instance);
            this.stream.Merge(next); 
        }
    }
    private IObservable<EventArgs> Init(Foo instance)
    {
            return Observable.FromEvent
                <EventHandler<EventArgs>, EventArgs>(handler =>
                          {
                              EventHandler<EventArgs> eh = (sender, e) => {
                                  handler(e);
                              };
                              return eh;
                          },
                          eh => instance.SomeEvent += eh ,
                          eh => instance.SomeEvent -= eh )
                             .Repeat()
                             .Retry()
                             .Publish()
                             .RefCount();
    }
    public void Dispose()
    {
    }
    public IDisposable Subscribe(IObserver<EventArgs> observer)
    {
        return stream.Subscribe(observer);
    }
}

合并从多个实例激发的事件的可观察序列的正确方法

像这样滥用Merge不是很有效。最直接的方法是通过Subject,这是一个可以手动控制的I观察对象。

public static class MyAwesomeFooFactory
{
    readonly static Subject<SomeEventArgs> someEvents = new Subject<SomeEventArgs>();
    public static IObservable<SomeEventArgs> NotificationsFromAllTheEvents { get { return someEvent; }}
    public static Foo MakeANewFoo()
    {
        var ret = new Foo();
        ret.SomeEvent.Subscribe(someEvents); // NB: We never unsubscribe, *evar*
        return ret;
    }
}

这不太可能像您想要的那样工作,并且可能存在破坏堆栈的性能问题。对于添加的每个实例,都会在第一个实例和最后一个观察者之间向堆栈添加另一个调用。得到太多的实例,你可能会毁掉堆栈。

更重要的是潜在的错误功能。观察者是否希望从订阅后创建的所有Foo获得通知?在你目前的设计中,它们不会。如果他们应该得到通知,您应该将stream更改为Subject<EventArgs>,并让它订阅每个Foo。主题将作为一个合并点,其好处是主题的所有订阅者都将从观察者订阅后创建的实例中获得消息。