From 8a4b3e33cf83d55380215c13e409b59f5e01ed64 Mon Sep 17 00:00:00 2001 From: Daniel Weber Date: Wed, 20 Jun 2018 17:49:27 +0200 Subject: [PATCH] Add an AnonymousDisposable that can be given a state object. Add a generic Disposable.Create method. --- .../Disposables/AnonymousDisposable.cs | 36 +++++++++++++++++++ .../System.Reactive/Disposables/Disposable.cs | 15 ++++++++ .../Api/ApiApprovalTests.Core.approved.txt | 1 + 3 files changed, 52 insertions(+) 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 {