diff --git a/Rx.NET/Source/src/System.Reactive/Disposables/AnonymousDisposable.cs b/Rx.NET/Source/src/System.Reactive/Disposables/AnonymousDisposable.cs index 83347dac96..ff009a55d6 100644 --- a/Rx.NET/Source/src/System.Reactive/Disposables/AnonymousDisposable.cs +++ b/Rx.NET/Source/src/System.Reactive/Disposables/AnonymousDisposable.cs @@ -37,4 +37,40 @@ public void Dispose() Interlocked.Exchange(ref _dispose, null)?.Invoke(); } } + + /// + /// Represents a Action-based disposable that can hold onto some state. + /// + internal sealed class AnonymousDisposable : ICancelable + { + private TState _state; + private volatile Action _dispose; + + /// + /// Constructs a new disposable with the given action used for disposal. + /// + /// The state to be passed to the disposal action. + /// Disposal action which will be run upon calling Dispose. + public AnonymousDisposable(TState state, Action dispose) + { + System.Diagnostics.Debug.Assert(dispose != null); + + _state = state; + _dispose = dispose; + } + + /// + /// Gets a value that indicates whether the object is disposed. + /// + public bool IsDisposed => _dispose == null; + + /// + /// Calls the disposal action if and only if the current instance hasn't been disposed yet. + /// + public void Dispose() + { + Interlocked.Exchange(ref _dispose, null)?.Invoke(_state); + _state = default; + } + } } diff --git a/Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs b/Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs index ae75070f59..1de3e3cbfa 100644 --- a/Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs +++ b/Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs @@ -60,6 +60,21 @@ public static IDisposable Create(Action dispose) return new AnonymousDisposable(dispose); } + /// + /// Creates a disposable object that invokes the specified action when disposed. + /// + /// The state to be passed to the action. + /// Action to run during the first call to . The action is guaranteed to be run at most once. + /// The disposable object that runs the given action upon disposal. + /// is null. + public static IDisposable Create(TState state, Action dispose) + { + if (dispose == null) + throw new ArgumentNullException(nameof(dispose)); + + return new AnonymousDisposable(state, dispose); + } + /// /// Gets the value stored in or a null if /// was already disposed. diff --git a/Rx.NET/Source/tests/Tests.System.Reactive.ApiApprovals/Api/ApiApprovalTests.Core.approved.txt b/Rx.NET/Source/tests/Tests.System.Reactive.ApiApprovals/Api/ApiApprovalTests.Core.approved.txt index ac5e63583b..a4016d0d9f 100644 --- a/Rx.NET/Source/tests/Tests.System.Reactive.ApiApprovals/Api/ApiApprovalTests.Core.approved.txt +++ b/Rx.NET/Source/tests/Tests.System.Reactive.ApiApprovals/Api/ApiApprovalTests.Core.approved.txt @@ -568,6 +568,7 @@ namespace System.Reactive.Disposables { public static System.IDisposable Empty { get; } public static System.IDisposable Create(System.Action dispose) { } + public static System.IDisposable Create(TState state, System.Action dispose) { } } public interface ICancelable : System.IDisposable {