CompositeDisposable
public sealed class CompositeDisposable : ICollection<IDisposable>, IEnumerable<IDisposable>, IEnumerable, ICancelable, IDisposable
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();
}
}
}