Automatic call to Dispose after OnCompleted, with Linq-to-Rx RRS feed

  • Question

  • Hi,

    Need a clarification about the automatic invocation of Dispose when OnCompleted is called, when we use Linq-to-Rx. Details:

    The MSDN Library has an example for using IObservable here: There the EndTransmission method of the observable (LocationTracker) makes a copy of the observers collection (using ToArray) before calling OnCompleted on each observer. It has to create this copy because the OnCompleted method is followed by an automatic call to Dispose. [This automatic call happens only when we subscribe to the output of a LINQ method such as Select etc, and not directly subscribe to the LocationTracker object (the original observable).] And Dispose removes the observer from the observers collection, so we get the exception “Collection was modified; enumeration operation may not execute.” on the next iteration in the foreach in OnCompleted. To prevent this the MSDN example uses a copy of the observers collection.

    The problem with this approach is that an unnecessary copy is created solely to facilitate removal from the collection member variable. However, notice right there that the last line of EndTransmission is a call to observers.Clear(). So why not leave the work of clearing the collection to the observable class and you (the RX framework) avoid making the call to Dispose internally? That way we wouldn't have to make a copy of the observers collection and at the same time be able to use foreach in EndTransmission.

    The observer class here (LocationReporter) has one string member variable instName (apart from the Unsubscriber reference). Making copies of a large number of observers makes that many unnecessary copies of these member variables.

    Since (from your videos) the sole purpose of Dispose here seems to be unsubscribing, the framework doesn't need to call Dispose here because a mass unsubscription is anyway achieved by the observable when it calls observers.Clear() in EndTransmission.

    Wes, What are your thoughts?


    Tuesday, June 1, 2010 7:38 AM


  • Hi Venkatesh,

    I just want to point out that it's a very basic sample.  More importantly, the sample doesn't conform to the IObservable contract as implemented by Rx:

      OnNext* (OnError | OnCompleted)?

    For example, it's possible that OnError will be called multiple times in the sample.

    Rx prevents this sort of thing internally for all of its built-in operators and for Observable.Create, which you can use to create your own operators.

    Essentially, when using Rx, OnCompleted automatically unsubscribes all observers to prevent any subsequent notifications.  Likewise for OnError, which the MSDN sample seems to ignore.

    I happen to agree with you though that the sample shouldn't bother unsubscribing at all in the IObserver implementation.  Instead, the EndTransmission method should probably just take a lock to prevent concurrent execution while it calls OnCompleted in the loop and also while it clears the collection afterwards.

    - Dave
    Tuesday, June 1, 2010 2:17 PM