// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // ActionOnDispose.cs // // // Implemention of IDisposable that runs a delegate on Dispose. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; namespace System.Threading.Tasks.Dataflow.Internal { /// Provider of disposables that run actions. internal sealed class Disposables { /// An IDisposable that does nothing. internal readonly static IDisposable Nop = new NopDisposable(); /// Creates an IDisposable that runs an action when disposed. /// Specifies the type of the first argument. /// Specifies the type of the second argument. /// The action to invoke. /// The first argument. /// The second argument. /// The created disposable. internal static IDisposable Create(Action action, T1 arg1, T2 arg2) { Contract.Requires(action != null, "Non-null disposer action required."); return new Disposable(action, arg1, arg2); } /// Creates an IDisposable that runs an action when disposed. /// Specifies the type of the first argument. /// Specifies the type of the second argument. /// Specifies the type of the third argument. /// The action to invoke. /// The first argument. /// The second argument. /// The third argument. /// The created disposable. internal static IDisposable Create(Action action, T1 arg1, T2 arg2, T3 arg3) { Contract.Requires(action != null, "Non-null disposer action required."); return new Disposable(action, arg1, arg2, arg3); } /// A disposable that's a nop. [DebuggerDisplay("Disposed = true")] private sealed class NopDisposable : IDisposable { void IDisposable.Dispose() { } } /// An IDisposable that will run a delegate when disposed. [DebuggerDisplay("Disposed = {Disposed}")] private sealed class Disposable : IDisposable { /// First state argument. private readonly T1 _arg1; /// Second state argument. private readonly T2 _arg2; /// The action to run when disposed. Null if disposed. private Action _action; /// Initializes the ActionOnDispose. /// The action to run when disposed. /// The first argument. /// The second argument. internal Disposable(Action action, T1 arg1, T2 arg2) { Contract.Requires(action != null, "Non-null action needed for disposable"); _action = action; _arg1 = arg1; _arg2 = arg2; } /// Gets whether the IDisposable has been disposed. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private bool Disposed { get { return _action == null; } } /// Invoke the action. void IDisposable.Dispose() { Action toRun = _action; if (toRun != null && Interlocked.CompareExchange(ref _action, null, toRun) == toRun) { toRun(_arg1, _arg2); } } } /// An IDisposable that will run a delegate when disposed. [DebuggerDisplay("Disposed = {Disposed}")] private sealed class Disposable : IDisposable { /// First state argument. private readonly T1 _arg1; /// Second state argument. private readonly T2 _arg2; /// Third state argument. private readonly T3 _arg3; /// The action to run when disposed. Null if disposed. private Action _action; /// Initializes the ActionOnDispose. /// The action to run when disposed. /// The first argument. /// The second argument. /// The third argument. internal Disposable(Action action, T1 arg1, T2 arg2, T3 arg3) { Contract.Requires(action != null, "Non-null action needed for disposable"); _action = action; _arg1 = arg1; _arg2 = arg2; _arg3 = arg3; } /// Gets whether the IDisposable has been disposed. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private bool Disposed { get { return _action == null; } } /// Invoke the action. void IDisposable.Dispose() { Action toRun = _action; if (toRun != null && Interlocked.CompareExchange(ref _action, null, toRun) == toRun) { toRun(_arg1, _arg2, _arg3); } } } } }