/// <summary> /// Subscribes an observer to the subject. /// </summary> public IDisposable Subscribe(IObserver <T> observer) { if (observer == null) { throw new ArgumentNullException("observer"); } var subscription = new RemovableDisposable(this, observer); var group = new CompositeDisposable(subscription); var myq = default(Queue <Timestamped <Notification <T> > >); lock (this.observers) { Trim(scheduler.Now); myq = new Queue <Timestamped <Notification <T> > >(q); qs.Add(myq); } group.Add(scheduler.Schedule(self => { var ts = default(Timestamped <Notification <T> >); lock (this.observers) { if (!subscription.IsStopped && myq.Count > 0) { ts = myq.Dequeue(); } else { qs.Remove(myq); observers.Add(observer); subscription.IsStarted = true; } } if (ts.Value != null) { ts.Value.Accept(observer); self(); } })); return(group); }
/// <summary> /// Subscribes an observer to the subject. /// </summary> /// <param name="observer">Observer to subscribe to the subject.</param> /// <returns>Disposable object that can be used to unsubscribe the observer from the subject.</returns> /// <exception cref="ArgumentNullException"><paramref name="observer"/> is null.</exception> public IDisposable Subscribe(IObserver <T> observer) { if (observer == null) { throw new ArgumentNullException("observer"); } var so = new ScheduledObserver <T>(_scheduler, observer); var n = 0; var subscription = new RemovableDisposable(this, so); lock (_gate) { CheckDisposed(); // // Notice the v1.x behavior of always calling Trim is preserved here. // // This may be subject (pun intended) of debate: should this policy // only be applied while the sequence is active? With the current // behavior, a sequence will "die out" after it has terminated by // continue to drop OnNext notifications from the queue. // // In v1.x, this behavior was due to trimming based on the clock value // returned by scheduler.Now, applied to all but the terminal message // in the queue. Using the IStopwatch has the same effect. Either way, // we guarantee the final notification will be observed, but there's // no way to retain the buffer directly. One approach is to use the // time-based TakeLast operator and apply an unbounded ReplaySubject // to it. // // To conclude, we're keeping the behavior as-is for compatibility // reasons with v1.x. // Trim(_stopwatch.Elapsed); _observers = _observers.Add(so); n = _queue.Count; foreach (var item in _queue) { so.OnNext(item.Value); } if (_error != null) { n++; so.OnError(_error); } else if (_isStopped) { n++; so.OnCompleted(); } } so.EnsureActive(n); return(subscription); }