# HG changeset patch # User cin # Date 2016-11-09 09:03:22 # Node ID 558f34b2fb50f2b375ca1a419c6d352e24139c84 # Parent 86b61d53b7db5c45fb6a519476de7e73f51481a9 added Safe.DispatchEvent() a legacy equivalent for '?.Invoke()' added Safe.Dispose(IEnumerable) added PromiseExtensions.CancellationPoint to add a cancellation point to the chain of promises added IPromise PromiseExtensions.Then(this IPromise that, Action success) overloads added PromiseExtensions.Error() overloads to handle a error or(and) a cancellation diff --git a/Implab/Components/StateChangeEventArgs.cs b/Implab/Components/StateChangeEventArgs.cs --- a/Implab/Components/StateChangeEventArgs.cs +++ b/Implab/Components/StateChangeEventArgs.cs @@ -2,7 +2,7 @@ namespace Implab.Components { - public class StateChangeEventArgs { + public class StateChangeEventArgs : EventArgs { /// /// The error information if any /// diff --git a/Implab/PromiseExtensions.cs b/Implab/PromiseExtensions.cs --- a/Implab/PromiseExtensions.cs +++ b/Implab/PromiseExtensions.cs @@ -47,7 +47,7 @@ namespace Implab { /// Cleanup. /// The 1st type parameter. /// The 2nd type parameter. - public static TPromise EnsureDispatched(this TPromise that, IPromise head, Action cleanup) where TPromise : IPromise{ + public static TPromise EnsureDispatched(this TPromise that, IPromise head, Action cleanup) where TPromise : IPromise { Safe.ArgumentNotNull(that, "that"); Safe.ArgumentNotNull(head, "head"); @@ -56,12 +56,37 @@ namespace Implab { return that; } - public static AsyncCallback AsyncCallback(this Promise that, Func callback) { + /// + /// Adds a cancellation point to the chain of promises. When a cancellation request reaches the cancellation point the operation is + /// cancelled immediatelly, and the request is passed towards. If the operation at the higher level can not be cancelled is't result + /// will be collected with callback. + /// + /// The type of the promise result. + /// The promise to which the cancellation point should be attached. + /// The callback which is used to cleanup the result of the operation if the cancellation point is cancelled already. + /// The promise + public static IPromise CancellationPoint(this IPromise that, Action cleanup) { + var meduim = new Promise(); + + that.On(meduim.Resolve, meduim.Reject, meduim.CancelOperation); + + meduim.CancellationRequested(that.Cancel); + meduim.CancellationRequested(meduim.CancelOperation); + + if (cleanup != null) + meduim.On((Action)null, null, (e) => { + that.On(cleanup); + }); + + return meduim; + } + + public static AsyncCallback AsyncCallback(this Promise that, Func callback) { Safe.ArgumentNotNull(that, "that"); Safe.ArgumentNotNull(callback, "callback"); var op = TraceContext.Instance.CurrentOperation; return ar => { - TraceContext.Instance.EnterLogicalOperation(op,false); + TraceContext.Instance.EnterLogicalOperation(op, false); try { that.Resolve(callback(ar)); } catch (Exception err) { @@ -74,9 +99,9 @@ namespace Implab { static void CancelByTimeoutCallback(object cookie) { ((ICancellable)cookie).Cancel(new TimeoutException()); - } - -/// + } + + /// /// Cancells promise after the specified timeout is elapsed. /// /// The promise to cancel on timeout. @@ -112,7 +137,7 @@ namespace Implab { } medium.On(() => { - foreach(var p2 in that) + foreach (var p2 in that) p2.Cancel(); }, PromiseEventType.ErrorOrCancel); @@ -148,7 +173,7 @@ namespace Implab { var results = new T[that.Count]; medium.On(() => { - foreach(var p2 in that) + foreach (var p2 in that) p2.Cancel(); }, PromiseEventType.ErrorOrCancel); @@ -216,12 +241,36 @@ namespace Implab { public static IPromise Then(this IPromise that, Func success, Func error, Func cancel) { Safe.ArgumentNotNull(that, "that"); - var d = new FuncTask(success, error, cancel, false); + var d = new FuncTask(success, error, cancel, false); that.On(d.Resolve, d.Reject, d.CancelOperation); d.CancellationRequested(that.Cancel); return d; } + public static IPromise Then(this IPromise that, Action success, Func error, Func cancel) { + Safe.ArgumentNotNull(that, "that"); + var d = new FuncTask( + x => { + success(x); + return x; + }, + error, + cancel, + false + ); + that.On(d.Resolve, d.Reject, d.CancelOperation); + d.CancellationRequested(that.Cancel); + return d; + } + + public static IPromise Then(this IPromise that, Action success, Func error) { + return Then(that, success, error, null); + } + + public static IPromise Then(this IPromise that, Action success) { + return Then(that, success, null, null); + } + public static IPromise Then(this IPromise that, Func success, Func error) { return Then(that, success, error, null); } @@ -230,8 +279,79 @@ namespace Implab { return Then(that, success, null, null); } + public static IPromise Always(this IPromise that, Action handler) { + Func errorOrCancel; + if (handler != null) + errorOrCancel = e => { + handler(); + throw new PromiseTransientException(e); + }; + else + errorOrCancel = null; + + return Then( + that, + x => { + handler(); + return x; + }, + errorOrCancel, + errorOrCancel); + } + + public static IPromise Always(this IPromise that, Action handler) { + Action errorOrCancel; + if (handler != null) + errorOrCancel = e => { + handler(); + throw new PromiseTransientException(e); + }; + else + errorOrCancel = null; + + return Then( + that, + handler, + errorOrCancel, + errorOrCancel); + } + + public static IPromise Error(this IPromise that, Action handler, bool handleCancellation) { + Action errorOrCancel; + if (handler != null) + errorOrCancel = e => { + handler(e); + throw new PromiseTransientException(e); + }; + else + errorOrCancel = null; + + return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null); + } + + public static IPromise Error(this IPromise that, Action handler) { + return Error(that, handler, false); + } + + public static IPromise Error(this IPromise that, Action handler, bool handleCancellation) { + Func errorOrCancel; + if (handler != null) + errorOrCancel = e => { + handler(e); + throw new PromiseTransientException(e); + }; + else + errorOrCancel = null; + + return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null); + } + + public static IPromise Error(this IPromise that, Action handler) { + return Error(that, handler, false); + } + #region chain traits - public static IPromise Chain(this IPromise that, Func success, Func error, Func cancel) { + public static IPromise Chain(this IPromise that, Func success, Func error, Func cancel) { Safe.ArgumentNotNull(that, "that"); var d = new ActionChainTask(success, error, cancel, false); @@ -240,7 +360,7 @@ namespace Implab { return d; } - public static IPromise Chain(this IPromise that, Func success, Func error) { + public static IPromise Chain(this IPromise that, Func success, Func error) { return Chain(that, success, error, null); } @@ -268,7 +388,7 @@ namespace Implab { public static IPromise Chain(this IPromise that, Func> success, Func> error, Func> cancel) { Safe.ArgumentNotNull(that, "that"); - var d = new FuncChainTask(success, error, cancel, false); + var d = new FuncChainTask(success, error, cancel, false); that.On(d.Resolve, d.Reject, d.CancelOperation); if (success != null) d.CancellationRequested(that.Cancel); @@ -281,20 +401,20 @@ namespace Implab { public static IPromise Chain(this IPromise that, Func> success) { return Chain(that, success, null, null); - } - + } + #endregion - - - #if NET_4_5 - + + +#if NET_4_5 + public static PromiseAwaiter GetAwaiter(this IPromise that) { Safe.ArgumentNotNull(that, "that"); return new PromiseAwaiter(that); - } - - #endif + } + +#endif } } diff --git a/Implab/Safe.cs b/Implab/Safe.cs --- a/Implab/Safe.cs +++ b/Implab/Safe.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; +using System.Collections; namespace Implab { @@ -60,12 +61,28 @@ namespace Implab } } + public static void Dispose(IEnumerable objects) { + foreach (var d in objects) + if (d != null) + d.Dispose(); + } + public static void Dispose(object obj) { var d = obj as IDisposable; if (d != null) d.Dispose(); } + public static void DispatchEvent(this EventHandler handler, object sender, T args) { + if (handler != null) + handler(sender, args); + } + + public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) { + if (handler != null) + handler(sender, args); + } + [DebuggerStepThrough] public static IPromise Run(Func action) { ArgumentNotNull(action, "action");