<PackageReference Include="System.Reactive" Version="4.1.2" />

CompositeDisposable

Represents a group of disposable resources that are disposed together.
using System.Collections; using System.Collections.Generic; using System.Threading; namespace System.Reactive.Disposables { public sealed class CompositeDisposable : ICollection<IDisposable>, IEnumerable<IDisposable>, IEnumerable, ICancelable, IDisposable { private sealed class CompositeEnumerator : IEnumerator<IDisposable>, IEnumerator, IDisposable { private readonly IDisposable[] _disposables; private int _index; public IDisposable Current => _disposables[_index]; object IEnumerator.Current { get { return _disposables[_index]; } } public CompositeEnumerator(IDisposable[] disposables) { _disposables = disposables; _index = -1; } public void Dispose() { IDisposable[] disposables = _disposables; Array.Clear(disposables, 0, disposables.Length); } public bool MoveNext() { IDisposable[] disposables = _disposables; int num; do { num = ++_index; if (num >= disposables.Length) return false; } while (disposables[num] == null); return true; } public void Reset() { _index = -1; } } private readonly object _gate = new object(); private bool _disposed; private List<IDisposable> _disposables; private int _count; private const int ShrinkThreshold = 64; private const int DefaultCapacity = 16; private static readonly CompositeEnumerator EmptyEnumerator = new CompositeEnumerator(Array.Empty<IDisposable>()); public int Count => Volatile.Read(ref _count); public bool IsReadOnly => false; public bool IsDisposed => Volatile.Read(ref _disposed); public CompositeDisposable() { _disposables = new List<IDisposable>(); } public CompositeDisposable(int capacity) { if (capacity < 0) throw new ArgumentOutOfRangeException("capacity"); _disposables = new List<IDisposable>(capacity); } public CompositeDisposable(params IDisposable[] disposables) { if (disposables == null) throw new ArgumentNullException("disposables"); Init(disposables, disposables.Length); } public CompositeDisposable(IEnumerable<IDisposable> disposables) { if (disposables == null) throw new ArgumentNullException("disposables"); ICollection<IDisposable> collection; if ((collection = (disposables as ICollection<IDisposable>)) != null) Init(disposables, collection.Count); else Init(disposables, 16); } private void Init(IEnumerable<IDisposable> disposables, int capacityHint) { List<IDisposable> list = new List<IDisposable>(capacityHint); foreach (IDisposable disposable in disposables) { if (disposable == null) throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables"); list.Add(disposable); } _disposables = list; Volatile.Write(ref _count, _disposables.Count); } public void Add(IDisposable item) { if (item == null) throw new ArgumentNullException("item"); lock (_gate) { if (!_disposed) { _disposables.Add(item); Volatile.Write(ref _count, _count + 1); return; } } item.Dispose(); } public bool Remove(IDisposable item) { if (item == null) throw new ArgumentNullException("item"); lock (_gate) { if (_disposed) return false; List<IDisposable> disposables = _disposables; int num = disposables.IndexOf(item); if (num < 0) return false; disposables[num] = null; if (disposables.Capacity > 64 && _count < disposables.Capacity / 2) { List<IDisposable> list = new List<IDisposable>(disposables.Capacity / 2); foreach (IDisposable item2 in disposables) { if (item2 != null) list.Add(item2); } _disposables = list; } Volatile.Write(ref _count, _count - 1); } item.Dispose(); return true; } public void Dispose() { List<IDisposable> list = null; lock (_gate) { if (!_disposed) { list = _disposables; _disposables = null; Volatile.Write(ref _count, 0); Volatile.Write(ref _disposed, true); } } if (list != null) { foreach (IDisposable item in list) { item?.Dispose(); } } } public void Clear() { IDisposable[] array = null; lock (_gate) { if (_disposed) return; List<IDisposable> disposables = _disposables; array = disposables.ToArray(); disposables.Clear(); Volatile.Write(ref _count, 0); } IDisposable[] array2 = array; for (int i = 0; i < array2.Length; i++) { array2[i]?.Dispose(); } } public bool Contains(IDisposable item) { if (item == null) throw new ArgumentNullException("item"); lock (_gate) { if (!_disposed) return _disposables.Contains(item); return false; } } public void CopyTo(IDisposable[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException("array"); if (arrayIndex < 0 || arrayIndex >= array.Length) throw new ArgumentOutOfRangeException("arrayIndex"); lock (_gate) { if (!_disposed) { if (arrayIndex + _count > array.Length) throw new ArgumentOutOfRangeException("arrayIndex"); int num = arrayIndex; foreach (IDisposable disposable in _disposables) { if (disposable != null) array[num++] = disposable; } } } } public IEnumerator<IDisposable> GetEnumerator() { lock (_gate) { if (!_disposed && _count != 0) return new CompositeEnumerator(_disposables.ToArray()); return EmptyEnumerator; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }