public void Dispose() { ReferenceCountedProviders oldRefCountedProviders = _refCountedProviders; // This lock ensures that we cannot reduce the ref count to zero before GetReference() calls AddReference(). // Once _disposed is set, GetReference() stops reference counting. lock (_replaceProvidersLock) { _disposed = true; } // Never dispose ReferenceCountedProviders with a lock because this may call into user code. oldRefCountedProviders.Dispose(); }
public ReferenceCountedProviders GetReference() { // Lock to ensure oldRefCountedProviders.Dispose() in ReplaceProviders() or Dispose() doesn't decrement ref count to zero // before calling _refCountedProviders.AddReference(). lock (_replaceProvidersLock) { if (_disposed) { // Return a non-reference-counting ReferenceCountedProviders instance now that the ConfigurationManager is disposed. // We could preemptively throw an ODE instead, but this might break existing apps that were previously able to // continue to read configuration after disposing an ConfigurationManager. return(ReferenceCountedProviders.CreateDisposed(_refCountedProviders.NonReferenceCountedProviders)); } _refCountedProviders.AddReference(); return(_refCountedProviders); } }
// Providers should never be concurrently modified. Reading during modification is allowed. public void ReplaceProviders(List <IConfigurationProvider> providers) { ReferenceCountedProviders oldRefCountedProviders = _refCountedProviders; lock (_replaceProvidersLock) { if (_disposed) { throw new ObjectDisposedException(nameof(ConfigurationManager)); } _refCountedProviders = ReferenceCountedProviders.Create(providers); } // Decrement the reference count to the old providers. If they are being concurrently read from // the actual disposal of the old providers will be delayed until the final reference is released. // Never dispose ReferenceCountedProviders with a lock because this may call into user code. oldRefCountedProviders.Dispose(); }