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.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Reactive.Disposables
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public sealed class CompositeDisposable : ICollection<IDisposable>, IEnumerable<IDisposable>, IEnumerable, ICancelable, IDisposable
{
[System.Runtime.CompilerServices.Nullable(0)]
private sealed class CompositeEnumerator : IEnumerator<IDisposable>, IDisposable, IEnumerator
{
[System.Runtime.CompilerServices.Nullable(new byte[] {
1,
2
})]
private readonly IDisposable[] _disposables;
private int _index;
public IDisposable Current => _disposables[_index];
object IEnumerator.Current {
get {
return _disposables[_index];
}
}
public CompositeEnumerator([System.Runtime.CompilerServices.Nullable(new byte[] {
1,
2
})] 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 object _disposables;
private int _count;
private const int ShrinkThreshold = 64;
private const int MaximumLinearSearchThreshold = 1024;
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");
(object, int) valueTuple = ToListOrDictionary(disposables);
_disposables = valueTuple.Item1;
Volatile.Write(ref _count, disposables.Length);
}
public CompositeDisposable(IEnumerable<IDisposable> disposables)
{
if (disposables == null)
throw new ArgumentNullException("disposables");
(object, int) valueTuple = ToListOrDictionary(disposables);
_disposables = valueTuple.Item1;
int item = valueTuple.Item2;
Volatile.Write(ref _count, item);
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private static (object Collection, int Count) ToListOrDictionary(IEnumerable<IDisposable> disposables)
{
IDisposable[] array = disposables as IDisposable[];
int num;
if (array == null) {
ICollection<IDisposable> collection = disposables as ICollection<IDisposable>;
num = ((collection == null) ? 16 : collection.Count);
} else
num = array.Length;
int num2 = num;
if (num2 > 1024) {
Dictionary<IDisposable, int> dictionary = new Dictionary<IDisposable, int>(num2);
int num3 = 0;
foreach (IDisposable disposable in disposables) {
if (disposable == null)
throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
dictionary.TryGetValue(disposable, out int value);
dictionary[disposable] = value + 1;
num3++;
}
return (dictionary, num3);
}
List<IDisposable> list = new List<IDisposable>(num2);
foreach (IDisposable disposable2 in disposables) {
if (disposable2 == null)
throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
list.Add(disposable2);
}
int count = list.Count;
return (list, list.Count);
}
public void Add(IDisposable item)
{
if (item == null)
throw new ArgumentNullException("item");
lock (_gate) {
if (!_disposed) {
List<IDisposable> list = _disposables as List<IDisposable>;
if (list != null) {
list.Add(item);
if (list.Count > 1024) {
Dictionary<IDisposable, int> dictionary = new Dictionary<IDisposable, int>(list.Count + list.Count / 4);
foreach (IDisposable item2 in list) {
if (item2 != null) {
dictionary.TryGetValue(item2, out int value);
dictionary[item2] = value + 1;
}
}
_disposables = dictionary;
}
} else {
Dictionary<IDisposable, int> obj = (Dictionary<IDisposable, int>)_disposables;
obj.TryGetValue(item, out int value2);
obj[item] = value2 + 1;
}
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> list = _disposables as List<IDisposable>;
if (list != null) {
int num = list.IndexOf(item);
if (num < 0)
return false;
list[num] = null;
if (list.Capacity > 64 && _count < list.Capacity / 2) {
List<IDisposable> list2 = new List<IDisposable>(list.Capacity / 2);
foreach (IDisposable item2 in list) {
if (item2 != null)
list2.Add(item2);
}
_disposables = list2;
}
} else {
Dictionary<IDisposable, int> dictionary = (Dictionary<IDisposable, int>)_disposables;
if (!dictionary.TryGetValue(item, out int value))
return false;
value--;
if (value == 0)
dictionary.Remove(item);
else
dictionary[item] = value;
}
Volatile.Write(ref _count, _count - 1);
}
item.Dispose();
return true;
}
public void Dispose()
{
List<IDisposable> list = null;
Dictionary<IDisposable, int> dictionary = null;
lock (_gate) {
if (!_disposed) {
list = (_disposables as List<IDisposable>);
dictionary = (_disposables as Dictionary<IDisposable, int>);
_disposables = null;
Volatile.Write(ref _count, 0);
Volatile.Write(ref _disposed, true);
}
}
if (list != null) {
foreach (IDisposable item in list) {
item?.Dispose();
}
}
if (dictionary != null) {
foreach (KeyValuePair<IDisposable, int> item2 in dictionary) {
item2.Key.Dispose();
}
}
}
public void Clear()
{
IDisposable[] array = default(IDisposable[]);
lock (_gate) {
if (_disposed)
return;
object disposables = _disposables;
List<IDisposable> list = disposables as List<IDisposable>;
if (list != null) {
array = list.ToArray();
list.Clear();
} else {
Dictionary<IDisposable, int> obj = (Dictionary<IDisposable, int>)disposables;
array = new IDisposable[obj.Count];
obj.Keys.CopyTo(array, 0);
obj.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) {
object disposables = _disposables;
return (disposables as List<IDisposable>)?.Contains(item) ?? ((Dictionary<IDisposable, int>)disposables).ContainsKey(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;
object disposables = _disposables;
List<IDisposable> list = disposables as List<IDisposable>;
if (list != null) {
foreach (IDisposable item in list) {
if (item != null)
array[num++] = item;
}
} else {
foreach (KeyValuePair<IDisposable, int> item2 in (Dictionary<IDisposable, int>)disposables) {
for (int i = 0; i < item2.Value; i++) {
array[num++] = item2.Key;
}
}
}
}
}
}
public IEnumerator<IDisposable> GetEnumerator()
{
lock (_gate) {
if (!_disposed && _count != 0) {
object disposables = _disposables;
List<IDisposable> list = disposables as List<IDisposable>;
return new CompositeEnumerator((list != null) ? list.ToArray() : ((Dictionary<IDisposable, int>)disposables).Keys.ToArray());
}
return EmptyEnumerator;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}