| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT License.
- // See the LICENSE file in the project root for more information.
- using System.Collections.Generic;
- using System.Threading;
- namespace System.Reactive.Disposables
- {
- /// <summary>
- /// Represents a group of disposable resources that are disposed together.
- /// </summary>
- public abstract class StableCompositeDisposable : ICancelable
- {
- /// <summary>
- /// Creates a new group containing two disposable resources that are disposed together.
- /// </summary>
- /// <param name="disposable1">The first disposable resource to add to the group.</param>
- /// <param name="disposable2">The second disposable resource to add to the group.</param>
- /// <returns>Group of disposable resources that are disposed together.</returns>
- 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);
- }
- /// <summary>
- /// Creates a new group of disposable resources that are disposed together.
- /// </summary>
- /// <param name="disposables">Disposable resources to add to the group.</param>
- /// <returns>Group of disposable resources that are disposed together.</returns>
- public static ICancelable Create(params IDisposable[] disposables)
- {
- if (disposables == null)
- {
- throw new ArgumentNullException(nameof(disposables));
- }
- return new NAryArray(disposables);
- }
- /// <summary>
- /// Creates a group of disposable resources that are disposed together
- /// and without copying or checking for nulls inside the group.
- /// </summary>
- /// <param name="disposables">The array of disposables that is trusted
- /// to not contain nulls and gives no need to defensively copy it.</param>
- /// <returns>Group of disposable resources that are disposed together.</returns>
- internal static ICancelable CreateTrusted(params IDisposable[] disposables)
- {
- return new NAryTrustedArray(disposables);
- }
- /// <summary>
- /// Creates a new group of disposable resources that are disposed together.
- /// </summary>
- /// <param name="disposables">Disposable resources to add to the group.</param>
- /// <returns>Group of disposable resources that are disposed together.</returns>
- public static ICancelable Create(IEnumerable<IDisposable> disposables)
- {
- if (disposables == null)
- {
- throw new ArgumentNullException(nameof(disposables));
- }
- return new NAryEnumerable(disposables);
- }
- /// <summary>
- /// Disposes all disposables in the group.
- /// </summary>
- public abstract void Dispose();
- /// <summary>
- /// Gets a value that indicates whether the object is disposed.
- /// </summary>
- 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.Dispose(ref _disposable1);
- Disposable.Dispose(ref _disposable2);
- }
- }
- private sealed class NAryEnumerable : StableCompositeDisposable
- {
- private volatile List<IDisposable>? _disposables;
- public NAryEnumerable(IEnumerable<IDisposable> disposables)
- {
- _disposables = new List<IDisposable>(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();
- }
- }
- }
- }
- private sealed class NAryArray : StableCompositeDisposable
- {
- private IDisposable[]? _disposables;
- public NAryArray(IDisposable[] disposables)
- {
- if (Array.IndexOf(disposables, null!) != -1)
- {
- throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, nameof(disposables));
- }
- var n = disposables.Length;
- var ds = new IDisposable[n];
- Array.Copy(disposables, 0, ds, 0, n);
- Volatile.Write(ref _disposables, ds);
- }
- public override bool IsDisposed => Volatile.Read(ref _disposables) == null;
- public override void Dispose()
- {
- var old = Interlocked.Exchange(ref _disposables, null);
- if (old != null)
- {
- foreach (var d in old)
- {
- d.Dispose();
- }
- }
- }
- }
- /// <summary>
- /// A stable composite that doesn't do defensive copy of
- /// the input disposable array nor checks it for null.
- /// </summary>
- private sealed class NAryTrustedArray : StableCompositeDisposable
- {
- private IDisposable[]? _disposables;
- public NAryTrustedArray(IDisposable[] disposables)
- {
- Volatile.Write(ref _disposables, disposables);
- }
- public override bool IsDisposed => Volatile.Read(ref _disposables) == null;
- public override void Dispose()
- {
- var old = Interlocked.Exchange(ref _disposables, null);
- if (old != null)
- {
- foreach (var d in old)
- {
- d.Dispose();
- }
- }
- }
- }
- }
- }
|