| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 | // Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the Apache 2.0 License.// See the LICENSE file in the project root for more information. using System.Threading;namespace System.Reactive.Disposables{    /// <summary>    /// Represents a disposable resource whose underlying disposable resource can be swapped for another disposable resource.    /// </summary>    public sealed class MultipleAssignmentDisposable : ICancelable    {        private IDisposable _current;        /// <summary>        /// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.MultipleAssignmentDisposable"/> class with no current underlying disposable.        /// </summary>        public MultipleAssignmentDisposable()        {        }        /// <summary>        /// Gets a value that indicates whether the object is disposed.        /// </summary>        public bool IsDisposed        {            get            {                // We use a sentinel value to indicate we've been disposed. This sentinel never leaks                // to the outside world (see the Disposable property getter), so no-one can ever assign                // this value to us manually.                return Volatile.Read(ref _current) == BooleanDisposable.True;            }        }        /// <summary>        /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.        /// </summary>        /// <remarks>If the MutableDisposable has already been disposed, assignment to this property causes immediate disposal of the given disposable object.</remarks>        public IDisposable Disposable        {            get            {                var a = Volatile.Read(ref _current);                // Don't leak the DISPOSED sentinel                if (a == BooleanDisposable.True)                {                    a = DefaultDisposable.Instance;                }                return a;            }            set            {                // Let's read the current value atomically (also prevents reordering).                var old = Volatile.Read(ref _current);                for (;;)                {                    // If it is the disposed instance, dispose the value.                    if (old == BooleanDisposable.True)                    {                        value?.Dispose();                        return;                    }                    // Atomically swap in the new value and get back the old.                    var b = Interlocked.CompareExchange(ref _current, value, old);                    // If the old and new are the same, the swap was successful and we can quit                    if (old == b)                    {                        return;                    }                    // Otherwise, make the old reference the current and retry.                    old = b;                }            }        }        /// <summary>        /// Disposes the underlying disposable as well as all future replacements.        /// </summary>        public void Dispose()        {            // Read the current atomically.            var a = Volatile.Read(ref _current);            // If it is the disposed instance, don't bother further.            if (a != BooleanDisposable.True)            {                // Atomically swap in the disposed instance.                a = Interlocked.Exchange(ref _current, BooleanDisposable.True);                // It is possible there was a concurrent Dispose call so don't need to call Dispose()                // on DISPOSED                if (a != BooleanDisposable.True)                {                    a?.Dispose();                }            }        }    }}
 |