Mercurial > pub > ImplabNet
changeset 207:558f34b2fb50 v2
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<T> PromiseExtensions.Then<T>(this IPromise<T> that, Action<T> success) overloads
added PromiseExtensions.Error() overloads to handle a error or(and) a cancellation
author | cin |
---|---|
date | Wed, 09 Nov 2016 12:03:22 +0300 |
parents | 86b61d53b7db |
children | 7d07503621fe |
files | Implab/Components/StateChangeEventArgs.cs Implab/PromiseExtensions.cs Implab/Safe.cs |
diffstat | 3 files changed, 159 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/Implab/Components/StateChangeEventArgs.cs Tue Oct 25 17:40:45 2016 +0300 +++ b/Implab/Components/StateChangeEventArgs.cs Wed Nov 09 12:03:22 2016 +0300 @@ -2,7 +2,7 @@ namespace Implab.Components { - public class StateChangeEventArgs { + public class StateChangeEventArgs : EventArgs { /// <summary> /// The error information if any /// </summary>
--- a/Implab/PromiseExtensions.cs Tue Oct 25 17:40:45 2016 +0300 +++ b/Implab/PromiseExtensions.cs Wed Nov 09 12:03:22 2016 +0300 @@ -47,7 +47,7 @@ /// <param name="cleanup">Cleanup.</param> /// <typeparam name="TPromise">The 1st type parameter.</typeparam> /// <typeparam name="T">The 2nd type parameter.</typeparam> - public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{ + public static TPromise EnsureDispatched<TPromise, T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise { Safe.ArgumentNotNull(that, "that"); Safe.ArgumentNotNull(head, "head"); @@ -56,12 +56,37 @@ return that; } - public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) { + /// <summary> + /// 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 <paramref name="cleanup"/> callback. + /// </summary> + /// <typeparam name="T">The type of the promise result.</typeparam> + /// <param name="that">The promise to which the cancellation point should be attached.</param> + /// <param name="cleanup">The callback which is used to cleanup the result of the operation if the cancellation point is cancelled already.</param> + /// <returns>The promise</returns> + public static IPromise<T> CancellationPoint<T>(this IPromise<T> that, Action<T> cleanup) { + var meduim = new Promise<T>(); + + that.On(meduim.Resolve, meduim.Reject, meduim.CancelOperation); + + meduim.CancellationRequested(that.Cancel); + meduim.CancellationRequested(meduim.CancelOperation); + + if (cleanup != null) + meduim.On((Action<T>)null, null, (e) => { + that.On(cleanup); + }); + + return meduim; + } + + public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult, T> 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 @@ static void CancelByTimeoutCallback(object cookie) { ((ICancellable)cookie).Cancel(new TimeoutException()); - } - -/// <summary> + } + + /// <summary> /// Cancells promise after the specified timeout is elapsed. /// </summary> /// <param name="that">The promise to cancel on timeout.</param> @@ -112,7 +137,7 @@ } medium.On(() => { - foreach(var p2 in that) + foreach (var p2 in that) p2.Cancel(); }, PromiseEventType.ErrorOrCancel); @@ -148,7 +173,7 @@ 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 @@ public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) { Safe.ArgumentNotNull(that, "that"); - var d = new FuncTask<T,T2>(success, error, cancel, false); + var d = new FuncTask<T, T2>(success, error, cancel, false); that.On(d.Resolve, d.Reject, d.CancelOperation); d.CancellationRequested(that.Cancel); return d; } + public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error, Func<Exception, T> cancel) { + Safe.ArgumentNotNull(that, "that"); + var d = new FuncTask<T, T>( + 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<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error) { + return Then(that, success, error, null); + } + + public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success) { + return Then(that, success, null, null); + } + public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) { return Then(that, success, error, null); } @@ -230,8 +279,79 @@ return Then(that, success, null, null); } + public static IPromise<T> Always<T>(this IPromise<T> that, Action handler) { + Func<Exception, T> 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<Exception> 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<Exception> handler, bool handleCancellation) { + Action<Exception> 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<Exception> handler) { + return Error(that, handler, false); + } + + public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler, bool handleCancellation) { + Func<Exception, T> 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<T> Error<T>(this IPromise<T> that, Action<Exception> handler) { + return Error(that, handler, false); + } + #region chain traits - public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error, Func<Exception,IPromise> cancel) { + public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) { Safe.ArgumentNotNull(that, "that"); var d = new ActionChainTask(success, error, cancel, false); @@ -240,7 +360,7 @@ return d; } - public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) { + public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error) { return Chain(that, success, error, null); } @@ -268,7 +388,7 @@ public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) { Safe.ArgumentNotNull(that, "that"); - var d = new FuncChainTask<T,T2>(success, error, cancel, false); + var d = new FuncChainTask<T, T2>(success, error, cancel, false); that.On(d.Resolve, d.Reject, d.CancelOperation); if (success != null) d.CancellationRequested(that.Cancel); @@ -281,20 +401,20 @@ public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) { return Chain(that, success, null, null); - } - + } + #endregion - - - #if NET_4_5 - + + +#if NET_4_5 + public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) { Safe.ArgumentNotNull(that, "that"); return new PromiseAwaiter<T>(that); - } - - #endif + } + +#endif } }
--- a/Implab/Safe.cs Tue Oct 25 17:40:45 2016 +0300 +++ b/Implab/Safe.cs Wed Nov 09 12:03:22 2016 +0300 @@ -4,6 +4,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; +using System.Collections; namespace Implab { @@ -60,12 +61,28 @@ } } + public static void Dispose(IEnumerable<IDisposable> 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<T>(this EventHandler<T> 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<T> Run<T>(Func<T> action) { ArgumentNotNull(action, "action");