// 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.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 resource to add to the group. /// The second disposable resource 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(nameof(disposable1)); } if (disposable2 == null) { throw new ArgumentNullException(nameof(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(nameof(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(nameof(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; } private sealed class Binary : StableCompositeDisposable { private IDisposable _disposable1; private IDisposable _disposable2; public Binary(IDisposable disposable1, IDisposable disposable2) { Volatile.Write(ref _disposable1, disposable1); Volatile.Write(ref _disposable2, disposable2); } public override bool IsDisposed => Disposable.GetIsDisposed(ref _disposable1); public override void Dispose() { Disposable.TryDispose(ref _disposable1); Disposable.TryDispose(ref _disposable2); } } private sealed 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, nameof(disposables)); } } public override bool IsDisposed => _disposables == null; public override void Dispose() { var old = Interlocked.Exchange(ref _disposables, null); if (old != null) { foreach (var d in old) { d.Dispose(); } } } } } }