1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 4 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 5 // 6 // ActionOnDispose.cs 7 // 8 // 9 // Implemention of IDisposable that runs a delegate on Dispose. 10 // 11 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 12 13 using System.Diagnostics; 14 using System.Diagnostics.CodeAnalysis; 15 using System.Diagnostics.Contracts; 16 17 namespace System.Threading.Tasks.Dataflow.Internal 18 { 19 /// <summary>Provider of disposables that run actions.</summary> 20 internal sealed class Disposables 21 { 22 /// <summary>An IDisposable that does nothing.</summary> 23 internal readonly static IDisposable Nop = new NopDisposable(); 24 25 /// <summary>Creates an IDisposable that runs an action when disposed.</summary> 26 /// <typeparam name="T1">Specifies the type of the first argument.</typeparam> 27 /// <typeparam name="T2">Specifies the type of the second argument.</typeparam> 28 /// <param name="action">The action to invoke.</param> 29 /// <param name="arg1">The first argument.</param> 30 /// <param name="arg2">The second argument.</param> 31 /// <returns>The created disposable.</returns> Create(Action<T1, T2> action, T1 arg1, T2 arg2)32 internal static IDisposable Create<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2) 33 { 34 Contract.Requires(action != null, "Non-null disposer action required."); 35 return new Disposable<T1, T2>(action, arg1, arg2); 36 } 37 38 /// <summary>Creates an IDisposable that runs an action when disposed.</summary> 39 /// <typeparam name="T1">Specifies the type of the first argument.</typeparam> 40 /// <typeparam name="T2">Specifies the type of the second argument.</typeparam> 41 /// <typeparam name="T3">Specifies the type of the third argument.</typeparam> 42 /// <param name="action">The action to invoke.</param> 43 /// <param name="arg1">The first argument.</param> 44 /// <param name="arg2">The second argument.</param> 45 /// <param name="arg3">The third argument.</param> 46 /// <returns>The created disposable.</returns> Create(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)47 internal static IDisposable Create<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3) 48 { 49 Contract.Requires(action != null, "Non-null disposer action required."); 50 return new Disposable<T1, T2, T3>(action, arg1, arg2, arg3); 51 } 52 53 /// <summary>A disposable that's a nop.</summary> 54 [DebuggerDisplay("Disposed = true")] 55 private sealed class NopDisposable : IDisposable 56 { IDisposable.Dispose()57 void IDisposable.Dispose() { } 58 } 59 60 /// <summary>An IDisposable that will run a delegate when disposed.</summary> 61 [DebuggerDisplay("Disposed = {Disposed}")] 62 private sealed class Disposable<T1, T2> : IDisposable 63 { 64 /// <summary>First state argument.</summary> 65 private readonly T1 _arg1; 66 /// <summary>Second state argument.</summary> 67 private readonly T2 _arg2; 68 /// <summary>The action to run when disposed. Null if disposed.</summary> 69 private Action<T1, T2> _action; 70 71 /// <summary>Initializes the ActionOnDispose.</summary> 72 /// <param name="action">The action to run when disposed.</param> 73 /// <param name="arg1">The first argument.</param> 74 /// <param name="arg2">The second argument.</param> Disposable(Action<T1, T2> action, T1 arg1, T2 arg2)75 internal Disposable(Action<T1, T2> action, T1 arg1, T2 arg2) 76 { 77 Contract.Requires(action != null, "Non-null action needed for disposable"); 78 _action = action; 79 _arg1 = arg1; 80 _arg2 = arg2; 81 } 82 83 /// <summary>Gets whether the IDisposable has been disposed.</summary> 84 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 85 private bool Disposed { get { return _action == null; } } 86 87 /// <summary>Invoke the action.</summary> IDisposable.Dispose()88 void IDisposable.Dispose() 89 { 90 Action<T1, T2> toRun = _action; 91 if (toRun != null && 92 Interlocked.CompareExchange(ref _action, null, toRun) == toRun) 93 { 94 toRun(_arg1, _arg2); 95 } 96 } 97 } 98 99 /// <summary>An IDisposable that will run a delegate when disposed.</summary> 100 [DebuggerDisplay("Disposed = {Disposed}")] 101 private sealed class Disposable<T1, T2, T3> : IDisposable 102 { 103 /// <summary>First state argument.</summary> 104 private readonly T1 _arg1; 105 /// <summary>Second state argument.</summary> 106 private readonly T2 _arg2; 107 /// <summary>Third state argument.</summary> 108 private readonly T3 _arg3; 109 /// <summary>The action to run when disposed. Null if disposed.</summary> 110 private Action<T1, T2, T3> _action; 111 112 /// <summary>Initializes the ActionOnDispose.</summary> 113 /// <param name="action">The action to run when disposed.</param> 114 /// <param name="arg1">The first argument.</param> 115 /// <param name="arg2">The second argument.</param> 116 /// <param name="arg3">The third argument.</param> Disposable(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)117 internal Disposable(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3) 118 { 119 Contract.Requires(action != null, "Non-null action needed for disposable"); 120 _action = action; 121 _arg1 = arg1; 122 _arg2 = arg2; 123 _arg3 = arg3; 124 } 125 126 /// <summary>Gets whether the IDisposable has been disposed.</summary> 127 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 128 private bool Disposed { get { return _action == null; } } 129 130 /// <summary>Invoke the action.</summary> IDisposable.Dispose()131 void IDisposable.Dispose() 132 { 133 Action<T1, T2, T3> toRun = _action; 134 if (toRun != null && 135 Interlocked.CompareExchange(ref _action, null, toRun) == toRun) 136 { 137 toRun(_arg1, _arg2, _arg3); 138 } 139 } 140 } 141 } 142 } 143