<PackageReference Include="System.Reactive" Version="6.0.0-preview.1" />

RefCountDisposable

public sealed class RefCountDisposable : ICancelable, IDisposable
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; } } } }