RefCountDisposable
Represents a disposable resource that only disposes its underlying disposable resource when all GetDisposabledependent disposable objects have been disposed.
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Reactive.Disposables
{
public sealed class RefCountDisposable : ICancelable, IDisposable
{
private sealed class InnerDisposable : IDisposable
{
[System.Runtime.CompilerServices.Nullable(2)]
private RefCountDisposable _parent;
[System.Runtime.CompilerServices.NullableContext(1)]
public InnerDisposable(RefCountDisposable parent)
{
_parent = parent;
}
public void Dispose()
{
Interlocked.Exchange(ref _parent, null)?.Release();
}
}
private readonly bool _throwWhenDisposed;
[System.Runtime.CompilerServices.Nullable(2)]
private IDisposable _disposable;
private int _count;
public bool IsDisposed => Volatile.Read(ref _count) == -2147483648;
[System.Runtime.CompilerServices.NullableContext(1)]
public RefCountDisposable(IDisposable disposable)
: this(disposable, false)
{
}
[System.Runtime.CompilerServices.NullableContext(1)]
public RefCountDisposable(IDisposable disposable, bool throwWhenDisposed)
{
if (disposable == null)
throw new ArgumentNullException("disposable");
_disposable = disposable;
_count = 0;
_throwWhenDisposed = throwWhenDisposed;
}
[System.Runtime.CompilerServices.NullableContext(1)]
public IDisposable GetDisposable()
{
int num = Volatile.Read(ref _count);
while (true) {
if (num == -2147483648) {
if (_throwWhenDisposed)
throw new ObjectDisposedException("RefCountDisposable");
return Disposable.Empty;
}
if ((num & 2147483647) == 2147483647)
throw new OverflowException($"""{2147483647}""");
int num2 = Interlocked.CompareExchange(ref _count, num + 1, num);
if (num2 == num)
break;
num = num2;
}
return new InnerDisposable(this);
}
public void Dispose()
{
int num = Volatile.Read(ref _count);
int num2;
while (true) {
if ((num & 2147483648) != 0)
return;
num2 = (num & 2147483647);
int value = -2147483648 | num2;
int num3 = Interlocked.CompareExchange(ref _count, value, num);
if (num3 == num)
break;
num = num3;
}
if (num2 == 0) {
_disposable?.Dispose();
_disposable = null;
}
}
private void Release()
{
int num = Volatile.Read(ref _count);
int num4;
while (true) {
int num2 = (int)(num & 2147483648);
int num3 = num & 2147483647;
num4 = (num2 | (num3 - 1));
int num5 = Interlocked.CompareExchange(ref _count, num4, num);
if (num5 == num)
break;
num = num5;
}
if (num4 == -2147483648) {
_disposable?.Dispose();
_disposable = null;
}
}
}
}