// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Threading; namespace System.Reactive.Disposables { /// /// Represents a group of disposable resources that are disposed together. /// public abstract class StableCompositeDisposable : ICancelable { /// /// Creates a new group containing two disposable resources that are disposed together. /// /// The first disposable resoruce to add to the group. /// The second disposable resoruce to add to the group. /// Group of disposable resources that are disposed together. public static ICancelable Create(IDisposable disposable1, IDisposable disposable2) { if (disposable1 == null) throw new ArgumentNullException("disposable1"); if (disposable2 == null) throw new ArgumentNullException("disposable2"); return new Binary(disposable1, disposable2); } /// /// Creates a new group of disposable resources that are disposed together. /// /// Disposable resources to add to the group. /// Group of disposable resources that are disposed together. public static ICancelable Create(params IDisposable[] disposables) { if (disposables == null) throw new ArgumentNullException("disposables"); return new NAry(disposables); } /// /// Creates a new group of disposable resources that are disposed together. /// /// Disposable resources to add to the group. /// Group of disposable resources that are disposed together. public static ICancelable Create(IEnumerable disposables) { if (disposables == null) throw new ArgumentNullException("disposables"); return new NAry(disposables); } /// /// Disposes all disposables in the group. /// public abstract void Dispose(); /// /// Gets a value that indicates whether the object is disposed. /// public abstract bool IsDisposed { get; } class Binary : StableCompositeDisposable { private volatile IDisposable _disposable1; private volatile IDisposable _disposable2; public Binary(IDisposable disposable1, IDisposable disposable2) { _disposable1 = disposable1; _disposable2 = disposable2; } public override bool IsDisposed { get { return _disposable1 == null; } } public override void Dispose() { #pragma warning disable 0420 var old1 = Interlocked.Exchange(ref _disposable1, null); #pragma warning restore 0420 if (old1 != null) { old1.Dispose(); } #pragma warning disable 0420 var old2 = Interlocked.Exchange(ref _disposable2, null); #pragma warning restore 0420 if (old2 != null) { old2.Dispose(); } } } class NAry : StableCompositeDisposable { private volatile List _disposables; public NAry(IDisposable[] disposables) : this((IEnumerable)disposables) { } public NAry(IEnumerable disposables) { _disposables = new List(disposables); // // Doing this on the list to avoid duplicate enumeration of disposables. // if (_disposables.Contains(null)) throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables"); } public override bool IsDisposed { get { return _disposables == null; } } public override void Dispose() { #pragma warning disable 0420 var old = Interlocked.Exchange(ref _disposables, null); #pragma warning restore 0420 if (old != null) { foreach (var d in old) { d.Dispose(); } } } } } }