Search code examples
.netsystem.reactiveobservable

Contract for IConnectableObservable.Connect with regards to multiple calls


What is the contract supposed to be for IConnectableObservable.Connect when it's called more than once?

When the IDisposable returned is disposed of should OnCompleted be published or should it just disconnect and allow Connect to be called a second time?

If Connect is called a second time before the first is disposed of, should it:

  • Throw
  • Return the same IDisposable, possibly having an unexpected dispose from different regions of code
  • Return a new IDisposable with some sort of Dispose reference counting and cause issues with a source you called Dispose on still publishing values

I'm trying to implement IConnectableObservable and the documentation for people implementing it is really light.


Solution

  • If you have a look at the source

    The answer to your first question (as of writing):

    When the IDisposable returned is disposed of should OnCompleted be published or should it just disconnect and allow Connect to be called a second time?

    Just disconnects

    If Connect is called a second time before the first is disposed of

    It should: Return the same IDisposable, possibly having an unexpected dispose from different regions of code

    For posterity sake the interesting code sections are:

            public void Dispose()
            {
                lock (_parent._gate)
                {
                    if (_subscription != null)
                    {
                        _subscription.Dispose();
                        _subscription = null;
    
                        _parent._connection = null;
                    }
                }
            }
    

    and

        public IDisposable Connect()
        {
            lock (_gate)
            {
                if (_connection == null)
                {
                    var subscription = _source.SubscribeSafe(_subject);
                    _connection = new Connection(this, subscription);
                }
    
                return _connection;
            }
        }
    

    As you can see in the above there is a single connection which is disposed and connected to within a lock block to prevent concurrent modification.