| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 | // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.using System.Threading;namespace System.Reactive.Disposables{    /// <summary>    /// Represents a disposable resource that only disposes its underlying disposable resource when all <see cref="GetDisposable">dependent disposable objects</see> have been disposed.    /// </summary>    public sealed class RefCountDisposable : ICancelable    {        private readonly object _gate = new object();        private IDisposable _disposable;        private bool _isPrimaryDisposed;        private int _count;        /// <summary>        /// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.RefCountDisposable"/> class with the specified disposable.        /// </summary>        /// <param name="disposable">Underlying disposable.</param>        /// <exception cref="ArgumentNullException"><paramref name="disposable"/> is null.</exception>        public RefCountDisposable(IDisposable disposable)        {            if (disposable == null)                throw new ArgumentNullException("disposable");            _disposable = disposable;            _isPrimaryDisposed = false;            _count = 0;        }        /// <summary>        /// Gets a value that indicates whether the object is disposed.        /// </summary>        public bool IsDisposed        {            get { return _disposable == null; }        }        /// <summary>        /// Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.        /// </summary>        /// <returns>A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.</returns>        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Backward compat + non-trivial work for a property getter.")]        public IDisposable GetDisposable()        {            lock (_gate)            {                if (_disposable == null)                {                    return Disposable.Empty;                }                else                {                    _count++;                    return new InnerDisposable(this);                }            }        }        /// <summary>        /// Disposes the underlying disposable only when all dependent disposables have been disposed.        /// </summary>        public void Dispose()        {            var disposable = default(IDisposable);            lock (_gate)            {                if (_disposable != null)                {                    if (!_isPrimaryDisposed)                    {                        _isPrimaryDisposed = true;                        if (_count == 0)                        {                            disposable = _disposable;                            _disposable = null;                        }                    }                }            }            if (disposable != null)                disposable.Dispose();        }        private void Release()        {            var disposable = default(IDisposable);            lock (_gate)            {                if (_disposable != null)                {                    _count--;                    System.Diagnostics.Debug.Assert(_count >= 0);                    if (_isPrimaryDisposed)                    {                        if (_count == 0)                        {                            disposable = _disposable;                            _disposable = null;                        }                    }                }            }            if (disposable != null)                disposable.Dispose();        }        sealed class InnerDisposable : IDisposable        {            private RefCountDisposable _parent;            public InnerDisposable(RefCountDisposable parent)            {                _parent = parent;            }            public void Dispose()            {                var parent = Interlocked.Exchange(ref _parent, null);                if (parent != null)                    parent.Release();            }        }    }}
 |