在这种情况下实现ObservableBase是最好还是有另一种方法?

时间:2015-06-09 12:48:05

标签: c# .net system.reactive observable

首先,我没有找到ObservableBase或AnonymousObservable的自定义实现的好例子。我不知道在我的情况下我需要实施哪一个。情况就是这样。

我使用的是第三方库,有一个类让我们称它为Producer,它允许我像objProducer.Attach(MyHandler)一样在其上设置委托。 MyHandler将接收来自制作人的消息。我正在尝试在Producer周围创建一个包装器,使其可观察,理想情况下它是一个独特的类型,而不是只创建一个observable实例(如Observable.Create)。

已编辑:第三方制作人具有以下界面

public delegate void ProducerMessageHandler(Message objMessage);
public class Producer : IDisposable {
   public void Start();
   public void Attach(ProducerMessageHandler fnHandler);
   public void Dispose();
}

正如我所提到的,我无法控制它的源代码。它的目的是这样使用:创建一个实例,调用Attach并传递一个委托,调用Start,它基本上在Producer接收或生成它们时,在提供的委托中启动接收消息。

我正在考虑创建公共class ProducerObservable : ObservableBase<Message>,以便当有人订阅它时,我会(Rx库会)将消息推送给观察者。看来我需要在我的ProducerObservable的构造函数中调用Attach,然后我需要以某种方式在附加到它的观察者上调用OnNext。这是否意味着我必须对所有这些进行编码:向类中添加观察者列表LinkedList<IObserver<Message>>,然后在ProducerObservable上调用SubscribeCore抽象方法时添加观察者?然后显然我能够枚举MyHandler中的LinkedList<IObserver<Message>>并为每一个调用OnNext。所有这些看起来都可行,但感觉并不完全正确。我希望.net反应式扩展可以更好地为这种情况做好准备,至少在基类的某个地方准备好LinkedList<IObserver<Message>>的实现。

3 个答案:

答案 0 :(得分:1)

在使用Rx的代码中,“Producer”对象通常是通过公共属性或方法公开IObservable<T>实例的对象。 Producer类本身实现IObservable<T>的情况并不常见,当它发生时,它通过使用Rx来完成繁重的工作。你绝对不想自己实现IObservable<T>

以下是将observable作为属性公开的示例:

public class Producer
{
    public Producer(ThirdPartyLib.Producer p)
    {
        var c = Observable.Create(observer =>
        {
            ProducerMessageHandler h = msg => observer.OnNext(msg);
            p.Attach(h);
            p.Start();

            return Disposable.Empty;
        }).Publish();

        // Connect the observable the first time someone starts
        // observing
        Stream = Observable.Create(observer =>
        {
            var subscription = c.Subscribe(observer);
            if (Interlocked.Exchange(ref _connected, 1) == 0)
            {
                c.Connect();
            }

            return subscription;
        });
    }

    private int _connected;
    public IObservable<Message> Stream { get; private set; }
}

以下是我们通过委托给Rx实际实现IObservable<T>的相同示例:

public class Producer : IObservable<Message>
{
    public Producer(ThirdPartyLib.Producer p)
    {
        var c = Observable.Create(observer =>
        {
            ProducerMessageHandler h = msg => observer.OnNext(msg);
            p.Attach(h);
            p.Start();

            return Disposable.Empty;
        }).Publish();

        // Connect the observable the first time someone starts
        // observing
        _stream = Observable.Create(observer =>
        {
            var subscription = c.Subscribe(observer);
            if (Interlocked.Exchange(ref _connected, 1) == 0)
            {
                c.Connect();
            }

            return subscription;
        });
    }

    private IObservable<Message> _stream;

    // implement IObservable<T> by delegating to Rx
    public IDisposable Subscribe(IObserver<Message> observer)
    {
        return _stream.Subscribe(observer);
    }
}

答案 1 :(得分:1)

在这里你应该做些什么才能成为Rx&#34;友好&#34;:

public static class ObservableProducer
{
    public static IObservable<Message> Create()
    {
        return 
            Observable.Using(() => new Producer(), p =>
                Observable.Create<Message>(o => 
                {
                    ProducerMessageHandler handler = m => o.OnNext(m);
                    p.Attach(handler);
                    return Disposable.Create(() => o.OnCompleted());
                }));
    }
}

您可以这样使用:

IObservable<Message> query = ObservableProducer.Create();

您应该允许为所有新订阅创建多个Producer个实例 - 这就是Rx的工作方式。

但是,如果您只想要一个Producer实例,请查看在此可观察对象上使用.Publish()

以下是如何确保单个Producer实例是&#34;自我管理&#34;:

IObservable<Message> query = ObservableProducer.Create().Publish().RefCount();

这将在第一个订阅上创建一个Producer实例,并保留Producer,直到不再有任何订阅。这使得它能够自​​我管理&#34;和一个更好的解决方案,滚动你自己的班级。

如果你必须实施自己的课程,那么你经常会犯错误。你作为这个问题的答案添加的课程有三个,我可以看到。

  1. 在附加消息处理程序后实例化主题。如果生产者在附加过程中创建了一条消息,则代码将失败。
  2. 您不会跟踪订阅。如果您没有跟踪订阅,则无法处理它们。 Rx查询可以保存昂贵的资源,因此您应该尽早处理它们。
  3. 在处置制作人之前,您不会就此问题致电.OnCompleted()
  4. 这是我的班级实施:

    public class ProducerObservable : IObservable<Message>, IDisposable
    {
        private readonly Producer _Producer;
        private readonly Subject<Message> _Subject;
        private readonly CompositeDisposable _Disposables;
    
        public ProducerObservable()
        {
            _Subject = new Subject<Message>();
            ProducerMessageHandler fnHandler = m => _Subject.OnNext(m);
    
            _Producer = new Producer();
            _Producer.Attach(fnHandler);
            _Producer.Start();
    
            _Disposables = new CompositeDisposable();
            _Disposables.Add(_Producer);
            _Disposables.Add(_Subject);
        }
    
        public void Dispose()
        {
            _Subject.OnCompleted();
            _Disposables.Dispose();
        }
    
        public IDisposable Subscribe(IObserver<Message> objObserver)
        {
            var subscription = _Subject.Subscribe(objObserver);
            _Disposables.Add(subscription);
            return subscription;
        }
    }
    

    我仍然不喜欢它。在撰写本文时,我是[system.reactive]中有三个带银徽章的人中的一个(没有人还有金币),而且我从未实现过我自己的观察。我只是意识到我没有就这个问题打电话给.OnCompleted(),所以我回去编辑了上面的代码。这是一个雷区。它依靠内置的运营商来做得更好。

    ObservableBase存在的原因是为了防止人们犯错误,但它并没有阻止它。

答案 2 :(得分:0)

这次讨论给了我一个想法。这不是吗?

public class ProducerObservable : IObservable<Message>, IDisposable {
   private readonly Producer _Producer;
   private readonly Subject<Message> _Subject;

   public ProducerObservable() {
      _Produder = new Producer();
      _Producer.Attach(Message_Received);
      _Subject = new Subject<Message>();
      _Producer.Start();
   }

   public void Dispose() {
      _Producer.Dispose();
      _Subject.Dispose();
   }

   public IDisposable Subscribe(IObserver<Message> objObserver) {
      return _Subject.Subscribe(objObserver);
   }

   private void Message_Received(Message objMessage) {
      _Subject.OnNext(objMessage);
   }
}

因此,在我看来,我们避免额外的水平,额外的观察,只有一个可观察的类型,基本上我只看到优点,没有缺点。