From 55f661beedc4e7afbabf16adb1c8fa7b7df41d4e Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 14:08:18 -0700 Subject: [PATCH 01/10] Join Promise ancestory --- C-Sharp-Promise.csproj | 1 + Promise.cs | 273 ++++++++++++++------------------------- Promise_Base.cs | 252 ++++++++++++++++++++++++++++++++++++ Promise_NonGeneric.cs | 286 ++++++++++++----------------------------- 4 files changed, 431 insertions(+), 381 deletions(-) create mode 100644 Promise_Base.cs diff --git a/C-Sharp-Promise.csproj b/C-Sharp-Promise.csproj index 8b99fa3..78bb748 100644 --- a/C-Sharp-Promise.csproj +++ b/C-Sharp-Promise.csproj @@ -41,6 +41,7 @@ + diff --git a/Promise.cs b/Promise.cs index d96b9ff..2170939 100644 --- a/Promise.cs +++ b/Promise.cs @@ -10,12 +10,12 @@ namespace RSG /// Implements a C# promise. /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise /// - public interface IPromise + public interface IPromise: IPromiseBase { /// /// Set the name of the promise, useful for debugging. /// - IPromise WithName(string name); + new IPromise WithName(string name); /// /// Completes the promise. @@ -31,15 +31,10 @@ public interface IPromise /// void Done(Action onResolved); - /// - /// Complete the promise. Adds a default error handler. - /// - void Done(); - /// /// Handle errors for the promise. /// - IPromise Catch(Action onRejected); + new IPromise Catch(Action onRejected); /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). @@ -118,17 +113,6 @@ public interface IPromise IPromise ThenRace(Func> chain); } - /// - /// Interface for a promise that can be rejected. - /// - public interface IRejectable - { - /// - /// Reject the promise with an exception. - /// - void Reject(Exception ex); - } - /// /// Interface for a promise that can be rejected or resolved. /// @@ -140,79 +124,28 @@ public interface IPendingPromise : IRejectable void Resolve(PromisedT value); } - /// - /// Specifies the state of a promise. - /// - public enum PromiseState - { - Pending, // The promise is in-flight. - Rejected, // The promise has been rejected. - Resolved // The promise has been resolved. - }; - /// /// Implements a C# promise. /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise /// - public class Promise : IPromise, IPendingPromise, IPromiseInfo + public class Promise : Promise_Base, IPromise, IPendingPromise { - /// - /// The exception when the promise is rejected. - /// - private Exception rejectionException; - /// /// The value when the promises is resolved. /// private PromisedT resolveValue; - /// - /// Error handler. - /// - private List rejectHandlers; - /// /// Completed handlers that accept a value. /// private List> resolveCallbacks; private List resolveRejectables; - /// - /// ID of the promise, useful for debugging. - /// - public int Id { get; private set; } - - /// - /// Name of the promise, when set, useful for debugging. - /// - public string Name { get; private set; } + public Promise() : base() + { } - /// - /// Tracks the current state of the promise. - /// - public PromiseState CurState { get; private set; } - - public Promise() + public Promise(Action, Action> resolver) : this() { - this.CurState = PromiseState.Pending; - this.Id = ++Promise.nextPromiseId; - - if (Promise.EnablePromiseTracking) - { - Promise.pendingPromises.Add(this); - } - } - - public Promise(Action, Action> resolver) - { - this.CurState = PromiseState.Pending; - this.Id = ++Promise.nextPromiseId; - - if (Promise.EnablePromiseTracking) - { - Promise.pendingPromises.Add(this); - } - try { resolver( @@ -229,19 +162,6 @@ public Promise(Action, Action> resolver) } } - /// - /// Add a rejection handler for this promise. - /// - private void AddRejectHandler(Action onRejected, IRejectable rejectable) - { - if (rejectHandlers == null) - { - rejectHandlers = new List(); - } - - rejectHandlers.Add(new RejectHandler() { callback = onRejected, rejectable = rejectable }); ; - } - /// /// Add a resolve handler for this promise. /// @@ -261,49 +181,16 @@ private void AddResolveHandler(Action onResolved, IRejectable rejecta resolveRejectables.Add(rejectable); } - /// - /// Invoke a single handler. - /// - private void InvokeHandler(Action callback, IRejectable rejectable, T value) - { -// Argument.NotNull(() => callback); -// Argument.NotNull(() => rejectable); - - try - { - callback(value); - } - catch (Exception ex) - { - rejectable.Reject(ex); - } - } - /// /// Helper function clear out all handlers after resolution or rejection. /// - private void ClearHandlers() + protected override void ClearHandlers() { - rejectHandlers = null; + base.ClearHandlers(); resolveCallbacks = null; resolveRejectables = null; } - /// - /// Invoke all reject handlers. - /// - private void InvokeRejectHandlers(Exception ex) - { -// Argument.NotNull(() => ex); - - if (rejectHandlers != null) - { - rejectHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, ex)); - } - - ClearHandlers(); - } - /// /// Invoke all resolve handlers. /// @@ -319,29 +206,6 @@ private void InvokeResolveHandlers(PromisedT value) ClearHandlers(); } - /// - /// Reject the promise with an exception. - /// - public void Reject(Exception ex) - { -// Argument.NotNull(() => ex); - - if (CurState != PromiseState.Pending) - { - throw new ApplicationException("Attempt to reject a promise that is already in state: " + CurState + ", a promise can only be rejected when it is still in state: " + PromiseState.Pending); - } - - rejectionException = ex; - CurState = PromiseState.Rejected; - - if (Promise.EnablePromiseTracking) - { - Promise.pendingPromises.Remove(this); - } - - InvokeRejectHandlers(ex); - } - /// /// Resolve the promise with a particular value. /// @@ -389,25 +253,56 @@ public void Done(Action onResolved) ); } - /// - /// Complete the promise. Adds a default error handler. - /// - public void Done() - { - Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Set the name of the promise, useful for debugging. - /// - public IPromise WithName(string name) + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + public void Done(Action onResolved, Action onRejected) + { + Then((x) => { onResolved(); }, onRejected) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + public void Done(Action onResolved) + { + Then((x) => { onResolved(); }) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Complete the promise. Adds a defualt error handler. + /// + public void Done() + { + Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Set the name of the promise, useful for debugging. + /// + public IPromise WithName(string name) { this.Name = name; return this; } + IPromiseBase IPromiseBase.WithName(string name) + { + return WithName(name); + } + /// /// Handle errors for the promise. /// @@ -435,6 +330,11 @@ public IPromise Catch(Action onRejected) return resultPromise; } + IPromiseBase IPromiseBase.Catch(Action onRejected) + { + return Catch(onRejected); + } + /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). /// @@ -451,6 +351,11 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } + IPromiseBase IPromiseBase.Then(Func onResolved) + { + return Then((x) => { onResolved(); }, null); + } + /// /// Add a resolved callback. /// @@ -459,11 +364,16 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - public IPromise Then(Func> onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Action onResolved) + { + return Then((x) => { onResolved(); }, null); + } + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + public IPromise Then(Func> onResolved, Action onRejected) { // This version of the function must supply an onResolved. // Otherwise there is now way to get the converted value to pass to the resulting promise. @@ -537,10 +447,15 @@ public IPromise Then(Func onResolved, Action onR return resultPromise; } - /// - /// Add a resolved callback and a rejected callback. - /// - public IPromise Then(Action onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + { + return Then((x) => { onResolved(); }, onRejected); + } + + /// + /// Add a resolved callback and a rejected callback. + /// + public IPromise Then(Action onResolved, Action onRejected) { var resultPromise = new Promise(); resultPromise.WithName(Name); @@ -570,11 +485,16 @@ public IPromise Then(Action onResolved, Action return resultPromise; } - /// - /// Return a new promise with a different value. - /// May also change the type of the value. - /// - public IPromise Then(Func transform) + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + { + return Then((x) => { onResolved(); }, onRejected); + } + + /// + /// Return a new promise with a different value. + /// May also change the type of the value. + /// + public IPromise Then(Func transform) { // Argument.NotNull(() => transform); return Then(value => Promise.Resolved(transform(value))); @@ -633,6 +553,11 @@ public IPromise ThenAll(Func> chain) return Then(value => Promise.All(chain(value))); } + IPromiseBase IPromiseBase.ThenAll(Func> chain) + { + return ThenAll((x) => { return chain(); }); + } + /// /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. /// Returns a promise of a collection of the resolved results. @@ -769,7 +694,7 @@ public static IPromise Resolved(PromisedT promisedValue) /// /// Convert an exception directly into a rejected promise. /// - public static IPromise Rejected(Exception ex) + new public static IPromise Rejected(Exception ex) { // Argument.NotNull(() => ex); diff --git a/Promise_Base.cs b/Promise_Base.cs new file mode 100644 index 0000000..583a619 --- /dev/null +++ b/Promise_Base.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using RSG.Promises; + +namespace RSG +{ + public interface IPromiseBase + { + IPromiseBase WithName(string name); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void Done(Action onResolved, Action onRejected); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void Done(Action onResolved); + + /// + /// Complete the promise. Adds a default error handler. + /// + void Done(); + + /// + /// Handle errors for the promise. + /// + IPromiseBase Catch(Action onRejected); + + /// + /// Add a resolved callback that chains a non-value promise. + /// + IPromiseBase Then(Func onResolved); + + /// + /// Add a resolved callback. + /// + IPromiseBase Then(Action onResolved); + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + IPromiseBase Then(Func onResolved, Action onRejected); + + /// + /// Add a resolved callback and a rejected callback. + /// + IPromiseBase Then(Action onResolved, Action onRejected); + + /// + /// Chain an enumerable of promises, all of which must resolve. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromiseBase ThenAll(Func> chain); + } + + /// + /// Interface for a promise that can be rejected. + /// + public interface IRejectable + { + /// + /// Reject the promise with an exception. + /// + void Reject(Exception ex); + } + + /// + /// Arguments to the UnhandledError event. + /// + public class ExceptionEventArgs : EventArgs + { + internal ExceptionEventArgs(Exception exception) + { + // Argument.NotNull(() => exception); + + this.Exception = exception; + } + + public Exception Exception + { + get; + private set; + } + } + + /// + /// Represents a handler invoked when the promise is rejected. + /// + public struct RejectHandler + { + /// + /// Callback fn. + /// + public Action callback; + + /// + /// The promise that is rejected when there is an error while invoking the handler. + /// + public IRejectable rejectable; + } + + /// + /// Specifies the state of a promise. + /// + public enum PromiseState + { + Pending, // The promise is in-flight. + Rejected, // The promise has been rejected. + Resolved // The promise has been resolved. + }; + + /// + /// Used to list information of pending promises. + /// + public interface IPromiseInfo + { + /// + /// Id of the promise. + /// + int Id { get; } + + /// + /// Human-readable name for the promise. + /// + string Name { get; } + } + + public abstract class Promise_Base : IPromiseInfo + { + /// + /// The exception when the promise is rejected. + /// + protected Exception rejectionException; + + /// + /// Error handlers. + /// + protected List rejectHandlers; + + /// + /// ID of the promise, useful for debugging. + /// + public int Id { get; protected set; } + + /// + /// Name of the promise, when set, useful for debugging. + /// + public string Name { get; protected set; } + + /// + /// Tracks the current state of the promise. + /// + public PromiseState CurState { get; protected set; } + + public Promise_Base() + { + this.CurState = PromiseState.Pending; + this.Id = ++Promise.nextPromiseId; + + if (Promise.EnablePromiseTracking) + { + Promise.pendingPromises.Add(this); + } + } + + /// + /// Add a rejection handler for this promise. + /// + protected void AddRejectHandler(Action onRejected, IRejectable rejectable) + { + if (rejectHandlers == null) + { + rejectHandlers = new List(); + } + + rejectHandlers.Add(new RejectHandler() + { + callback = onRejected, + rejectable = rejectable + }); + } + + /// + /// Invoke a single handler. + /// + protected void InvokeHandler(Action callback, IRejectable rejectable, T value) + { + // Argument.NotNull(() => callback); + // Argument.NotNull(() => rejectable); + + try + { + callback(value); + } + catch (Exception ex) + { + rejectable.Reject(ex); + } + } + + protected virtual void ClearHandlers() + { + rejectHandlers = null; + } + + /// + /// Invoke all reject handlers. + /// + protected void InvokeRejectHandlers(Exception ex) + { + // Argument.NotNull(() => ex); + + if (rejectHandlers != null) + { + rejectHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, ex)); + } + + ClearHandlers(); + } + + /// + /// Reject the promise with an exception. + /// + public void Reject(Exception ex) + { + // Argument.NotNull(() => ex); + + if (CurState != PromiseState.Pending) + { + throw new ApplicationException("Attempt to reject a promise that is already in state: " + CurState + ", a promise can only be rejected when it is still in state: " + PromiseState.Pending); + } + + rejectionException = ex; + CurState = PromiseState.Rejected; + + if (Promise.EnablePromiseTracking) + { + Promise.pendingPromises.Remove(this); + } + + InvokeRejectHandlers(ex); + } + } +} diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index cc9905a..9d8c297 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -10,51 +10,32 @@ namespace RSG /// Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise /// - public interface IPromise + public interface IPromise : IPromiseBase { /// /// Set the name of the promise, useful for debugging. /// - IPromise WithName(string name); + new IPromise WithName(string name); - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// onRejected is called on error. - /// - void Done(Action onResolved, Action onRejected); - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// Adds a default error handler. - /// - void Done(Action onResolved); - - /// - /// Complete the promise. Adds a default error handler. - /// - void Done(); - - /// - /// Handle errors for the promise. - /// - IPromise Catch(Action onRejected); + /// + /// Handle errors for the promise. + /// + new IPromise Catch(Action onRejected); /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). /// IPromise Then(Func> onResolved); - /// - /// Add a resolved callback that chains a non-value promise. - /// - IPromise Then(Func onResolved); + /// + /// Add a resolved callback that chains a non-value promise. + /// + new IPromise Then(Func onResolved); - /// - /// Add a resolved callback. - /// - IPromise Then(Action onResolved); + /// + /// Add a resolved callback. + /// + new IPromise Then(Action onResolved); /// /// Add a resolved callback and a rejected callback. @@ -62,23 +43,23 @@ public interface IPromise /// IPromise Then(Func> onResolved, Action onRejected); - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a non-value promise. - /// - IPromise Then(Func onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + new IPromise Then(Func onResolved, Action onRejected); - /// - /// Add a resolved callback and a rejected callback. - /// - IPromise Then(Action onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// + new IPromise Then(Action onResolved, Action onRejected); - /// - /// Chain an enumerable of promises, all of which must resolve. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromise ThenAll(Func> chain); + /// + /// Chain an enumerable of promises, all of which must resolve. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + new IPromise ThenAll(Func> chain); /// /// Chain an enumerable of promises, all of which must resolve. @@ -121,62 +102,11 @@ public interface IPendingPromise : IRejectable void Resolve(); } - /// - /// Used to list information of pending promises. - /// - public interface IPromiseInfo - { - /// - /// Id of the promise. - /// - int Id { get; } - - /// - /// Human-readable name for the promise. - /// - string Name { get; } - } - - /// - /// Arguments to the UnhandledError event. - /// - public class ExceptionEventArgs : EventArgs - { - internal ExceptionEventArgs(Exception exception) - { -// Argument.NotNull(() => exception); - - this.Exception = exception; - } - - public Exception Exception - { - get; - private set; - } - } - - /// - /// Represents a handler invoked when the promise is rejected. - /// - public struct RejectHandler - { - /// - /// Callback fn. - /// - public Action callback; - - /// - /// The promise that is rejected when there is an error while invoking the handler. - /// - public IRejectable rejectable; - } - /// /// Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise /// - public class Promise : IPromise, IPendingPromise, IPromiseInfo + public class Promise : Promise_Base, IPromise, IPendingPromise { /// /// Set to true to enable tracking of promises. @@ -213,16 +143,6 @@ public static IEnumerable GetPendingPromises() return pendingPromises; } - /// - /// The exception when the promise is rejected. - /// - private Exception rejectionException; - - /// - /// Error handlers. - /// - private List rejectHandlers; - /// /// Represents a handler invoked when the promise is resolved. /// @@ -244,38 +164,11 @@ public struct ResolveHandler /// private List resolveHandlers; - /// - /// ID of the promise, useful for debugging. - /// - public int Id { get; private set; } - - /// - /// Name of the promise, when set, useful for debugging. - /// - public string Name { get; private set; } - - /// - /// Tracks the current state of the promise. - /// - public PromiseState CurState { get; private set; } - - public Promise() - { - this.CurState = PromiseState.Pending; - if (EnablePromiseTracking) - { - pendingPromises.Add(this); - } - } + public Promise() : base() + { } - public Promise(Action> resolver) + public Promise(Action> resolver): this() { - this.CurState = PromiseState.Pending; - if (EnablePromiseTracking) - { - pendingPromises.Add(this); - } - try { resolver( @@ -292,23 +185,6 @@ public Promise(Action> resolver) } } - /// - /// Add a rejection handler for this promise. - /// - private void AddRejectHandler(Action onRejected, IRejectable rejectable) - { - if (rejectHandlers == null) - { - rejectHandlers = new List(); - } - - rejectHandlers.Add(new RejectHandler() - { - callback = onRejected, - rejectable = rejectable - }); - } - /// /// Add a resolve handler for this promise. /// @@ -365,27 +241,12 @@ private void InvokeResolveHandler(Action callback, IRejectable rejectable) /// /// Helper function clear out all handlers after resolution or rejection. /// - private void ClearHandlers() + override protected void ClearHandlers() { - rejectHandlers = null; + base.ClearHandlers(); resolveHandlers = null; } - /// - /// Invoke all reject handlers. - /// - private void InvokeRejectHandlers(Exception ex) - { -// Argument.NotNull(() => ex); - - if (rejectHandlers != null) - { - rejectHandlers.Each(handler => InvokeRejectHandler(handler.callback, handler.rejectable, ex)); - } - - ClearHandlers(); - } - /// /// Invoke all resolve handlers. /// @@ -399,30 +260,6 @@ private void InvokeResolveHandlers() ClearHandlers(); } - /// - /// Reject the promise with an exception. - /// - public void Reject(Exception ex) - { -// Argument.NotNull(() => ex); - - if (CurState != PromiseState.Pending) - { - throw new ApplicationException("Attempt to reject a promise that is already in state: " + CurState + ", a promise can only be rejected when it is still in state: " + PromiseState.Pending); - } - - rejectionException = ex; - CurState = PromiseState.Rejected; - - if (EnablePromiseTracking) - { - pendingPromises.Remove(this); - } - - InvokeRejectHandlers(ex); - } - - /// /// Resolve the promise with a particular value. /// @@ -488,6 +325,11 @@ public IPromise WithName(string name) return this; } + IPromiseBase IPromiseBase.WithName(string name) + { + return WithName(name); + } + /// /// Handle errors for the promise. /// @@ -515,6 +357,11 @@ public IPromise Catch(Action onRejected) return resultPromise; } + IPromiseBase IPromiseBase.Catch(Action onRejected) + { + return Catch(onRejected); + } + /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). /// @@ -531,6 +378,11 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } + IPromiseBase IPromiseBase.Then(Func onResolved) + { + return Then(onResolved); + } + /// /// Add a resolved callback. /// @@ -539,11 +391,16 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - public IPromise Then(Func> onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Action onResolved) + { + return Then(onResolved); + } + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + public IPromise Then(Func> onResolved, Action onRejected) { // This version of the function must supply an onResolved. // Otherwise there is now way to get the converted value to pass to the resulting promise. @@ -617,6 +474,11 @@ public IPromise Then(Func onResolved, Action onRejected) return resultPromise; } + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + { + return Then(onResolved, onRejected); + } + /// /// Add a resolved callback and a rejected callback. /// @@ -650,10 +512,15 @@ public IPromise Then(Action onResolved, Action onRejected) return resultPromise; } - /// - /// Helper function to invoke or register resolve/reject handlers. - /// - private void ActionHandlers(IRejectable resultPromise, Action resolveHandler, Action rejectHandler) + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + { + return Then(onResolved, onRejected); + } + + /// + /// Helper function to invoke or register resolve/reject handlers. + /// + private void ActionHandlers(IRejectable resultPromise, Action resolveHandler, Action rejectHandler) { if (CurState == PromiseState.Resolved) { @@ -680,6 +547,11 @@ public IPromise ThenAll(Func> chain) return Then(() => Promise.All(chain())); } + IPromiseBase IPromiseBase.ThenAll(Func> chain) + { + return ThenAll(chain); + } + /// /// Chain an enumerable of promises, all of which must resolve. /// Converts to a non-value promise. From fae8f41240575ca2f8aa58d0da013e33da0f3dec Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 14:14:22 -0700 Subject: [PATCH 02/10] Fix warning --- Promise.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Promise.cs b/Promise.cs index 2170939..36e67ed 100644 --- a/Promise.cs +++ b/Promise.cs @@ -694,7 +694,7 @@ public static IPromise Resolved(PromisedT promisedValue) /// /// Convert an exception directly into a rejected promise. /// - new public static IPromise Rejected(Exception ex) + public static IPromise Rejected(Exception ex) { // Argument.NotNull(() => ex); From f495709cdfc0e537c856e3213b7cb7b355dc472b Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 15:28:00 -0700 Subject: [PATCH 03/10] Add comment --- Promise_Base.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Promise_Base.cs b/Promise_Base.cs index 583a619..1cba20f 100644 --- a/Promise_Base.cs +++ b/Promise_Base.cs @@ -6,6 +6,9 @@ namespace RSG { public interface IPromiseBase { + /// + /// Set the name of the promise, useful for debugging. + /// IPromiseBase WithName(string name); /// From e3b1319b74b0091c20fc17102431c3ea8ff1928e Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 15:59:30 -0700 Subject: [PATCH 04/10] Fix compile list --- C-Sharp-Promise.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C-Sharp-Promise.csproj b/C-Sharp-Promise.csproj index 78bb748..8755b48 100644 --- a/C-Sharp-Promise.csproj +++ b/C-Sharp-Promise.csproj @@ -41,7 +41,7 @@ - + From 6998a9e3a933ec8cc8a294a6710f77bd825548a9 Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 16:03:11 -0700 Subject: [PATCH 05/10] Make results available in IPromiseBase --- Promise.cs | 24 +++++++-------- Promise_Base.cs | 31 +++++++++++++++---- Promise_NonGeneric.cs | 72 +++++++++++++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/Promise.cs b/Promise.cs index 36e67ed..e13a72d 100644 --- a/Promise.cs +++ b/Promise.cs @@ -258,9 +258,9 @@ public void Done(Action onResolved) /// onResolved is called on successful completion. /// onRejected is called on error. /// - public void Done(Action onResolved, Action onRejected) + void IPromiseBase.Done(Action onResolved, Action onRejected) { - Then((x) => { onResolved(); }, onRejected) + Then((x) => { onResolved(new PromiseResult(x)); }, onRejected) .Catch(ex => Promise.PropagateUnhandledException(this, ex) ); @@ -271,9 +271,9 @@ public void Done(Action onResolved, Action onRejected) /// onResolved is called on successful completion. /// Adds a default error handler. /// - public void Done(Action onResolved) + void IPromiseBase.Done(Action onResolved) { - Then((x) => { onResolved(); }) + Then((x) => { onResolved(new PromiseResult(x)); }) .Catch(ex => Promise.PropagateUnhandledException(this, ex) ); @@ -351,9 +351,9 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Func onResolved) + IPromiseBase IPromiseBase.Then(Func onResolved) { - return Then((x) => { onResolved(); }, null); + return Then((x) => { onResolved(new PromiseResult(x)); }, null); } /// @@ -364,9 +364,9 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Action onResolved) + IPromiseBase IPromiseBase.Then(Action onResolved) { - return Then((x) => { onResolved(); }, null); + return Then((x) => { onResolved(new PromiseResult(x)); }, null); } /// @@ -447,9 +447,9 @@ public IPromise Then(Func onResolved, Action onR return resultPromise; } - IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) { - return Then((x) => { onResolved(); }, onRejected); + return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); } /// @@ -485,9 +485,9 @@ public IPromise Then(Action onResolved, Action return resultPromise; } - IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) { - return Then((x) => { onResolved(); }, onRejected); + return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); } /// diff --git a/Promise_Base.cs b/Promise_Base.cs index 1cba20f..026e9f4 100644 --- a/Promise_Base.cs +++ b/Promise_Base.cs @@ -16,14 +16,14 @@ public interface IPromiseBase /// onResolved is called on successful completion. /// onRejected is called on error. /// - void Done(Action onResolved, Action onRejected); + void Done(Action onResolved, Action onRejected); /// /// Completes the promise. /// onResolved is called on successful completion. /// Adds a default error handler. /// - void Done(Action onResolved); + void Done(Action onResolved); /// /// Complete the promise. Adds a default error handler. @@ -38,23 +38,23 @@ public interface IPromiseBase /// /// Add a resolved callback that chains a non-value promise. /// - IPromiseBase Then(Func onResolved); + IPromiseBase Then(Func onResolved); /// /// Add a resolved callback. /// - IPromiseBase Then(Action onResolved); + IPromiseBase Then(Action onResolved); /// /// Add a resolved callback and a rejected callback. /// The resolved callback chains a non-value promise. /// - IPromiseBase Then(Func onResolved, Action onRejected); + IPromiseBase Then(Func onResolved, Action onRejected); /// /// Add a resolved callback and a rejected callback. /// - IPromiseBase Then(Action onResolved, Action onRejected); + IPromiseBase Then(Action onResolved, Action onRejected); /// /// Chain an enumerable of promises, all of which must resolve. @@ -110,6 +110,25 @@ public struct RejectHandler public IRejectable rejectable; } + public class PromiseResult + { + public static readonly PromiseResult None = new PromiseResult(); + + public readonly bool hasValue; + public readonly object Result; + + public PromiseResult() + { + hasValue = false; + } + + public PromiseResult(object value) + { + hasValue = true; + Result = value; + } + } + /// /// Specifies the state of a promise. /// diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index 9d8c297..2f625f8 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -17,6 +17,20 @@ public interface IPromise : IPromiseBase /// new IPromise WithName(string name); + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void Done(Action onResolved, Action onRejected); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void Done(Action onResolved); + /// /// Handle errors for the promise. /// @@ -30,12 +44,12 @@ public interface IPromise : IPromiseBase /// /// Add a resolved callback that chains a non-value promise. /// - new IPromise Then(Func onResolved); + IPromise Then(Func onResolved); /// /// Add a resolved callback. /// - new IPromise Then(Action onResolved); + IPromise Then(Action onResolved); /// /// Add a resolved callback and a rejected callback. @@ -47,12 +61,12 @@ public interface IPromise : IPromiseBase /// Add a resolved callback and a rejected callback. /// The resolved callback chains a non-value promise. /// - new IPromise Then(Func onResolved, Action onRejected); + IPromise Then(Func onResolved, Action onRejected); /// /// Add a resolved callback and a rejected callback. /// - new IPromise Then(Action onResolved, Action onRejected); + IPromise Then(Action onResolved, Action onRejected); /// /// Chain an enumerable of promises, all of which must resolve. @@ -306,10 +320,36 @@ public void Done(Action onResolved) ); } - /// - /// Complete the promise. Adds a defualt error handler. - /// - public void Done() + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void IPromiseBase.Done(Action onResolved, Action onRejected) + { + Then(() => { onResolved(PromiseResult.None); }, onRejected) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void IPromiseBase.Done(Action onResolved) + { + Then(() => { onResolved(PromiseResult.None); }) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Complete the promise. Adds a defualt error handler. + /// + public void Done() { Catch(ex => Promise.PropagateUnhandledException(this, ex) @@ -378,9 +418,9 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Func onResolved) + IPromiseBase IPromiseBase.Then(Func onResolved) { - return Then(onResolved); + return Then(() => { onResolved(PromiseResult.None); }); } /// @@ -391,9 +431,9 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Action onResolved) + IPromiseBase IPromiseBase.Then(Action onResolved) { - return Then(onResolved); + return Then(() => { onResolved(PromiseResult.None); }); } /// @@ -474,9 +514,9 @@ public IPromise Then(Func onResolved, Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) { - return Then(onResolved, onRejected); + return Then(() => { onResolved(PromiseResult.None); }, onRejected); } /// @@ -512,9 +552,9 @@ public IPromise Then(Action onResolved, Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) { - return Then(onResolved, onRejected); + return Then(() => { onResolved(PromiseResult.None); }, onRejected); } /// From 9471f7ea276febfc00c71ec1363a2ff7bddb33a2 Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Thu, 23 Jun 2016 16:23:37 -0700 Subject: [PATCH 06/10] Spaces -> Tabs --- Promise.cs | 170 +++++++------- Promise_Base.cs | 534 +++++++++++++++++++++--------------------- Promise_NonGeneric.cs | 218 ++++++++--------- 3 files changed, 461 insertions(+), 461 deletions(-) diff --git a/Promise.cs b/Promise.cs index e13a72d..ac7f699 100644 --- a/Promise.cs +++ b/Promise.cs @@ -141,8 +141,8 @@ public class Promise : Promise_Base, IPromise, IPendingPro private List> resolveCallbacks; private List resolveRejectables; - public Promise() : base() - { } + public Promise() : base() + { } public Promise(Action, Action> resolver) : this() { @@ -186,7 +186,7 @@ private void AddResolveHandler(Action onResolved, IRejectable rejecta /// protected override void ClearHandlers() { - base.ClearHandlers(); + base.ClearHandlers(); resolveCallbacks = null; resolveRejectables = null; } @@ -253,55 +253,55 @@ public void Done(Action onResolved) ); } - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// onRejected is called on error. - /// - void IPromiseBase.Done(Action onResolved, Action onRejected) - { - Then((x) => { onResolved(new PromiseResult(x)); }, onRejected) - .Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// Adds a default error handler. - /// - void IPromiseBase.Done(Action onResolved) - { - Then((x) => { onResolved(new PromiseResult(x)); }) - .Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Complete the promise. Adds a defualt error handler. - /// - public void Done() - { - Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Set the name of the promise, useful for debugging. - /// - public IPromise WithName(string name) + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void IPromiseBase.Done(Action onResolved, Action onRejected) + { + Then((x) => { onResolved(new PromiseResult(x)); }, onRejected) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void IPromiseBase.Done(Action onResolved) + { + Then((x) => { onResolved(new PromiseResult(x)); }) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Complete the promise. Adds a defualt error handler. + /// + public void Done() + { + Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Set the name of the promise, useful for debugging. + /// + public IPromise WithName(string name) { this.Name = name; return this; } - IPromiseBase IPromiseBase.WithName(string name) - { - return WithName(name); - } + IPromiseBase IPromiseBase.WithName(string name) + { + return WithName(name); + } /// /// Handle errors for the promise. @@ -330,10 +330,10 @@ public IPromise Catch(Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Catch(Action onRejected) - { - return Catch(onRejected); - } + IPromiseBase IPromiseBase.Catch(Action onRejected) + { + return Catch(onRejected); + } /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). @@ -351,10 +351,10 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Func onResolved) - { - return Then((x) => { onResolved(new PromiseResult(x)); }, null); - } + IPromiseBase IPromiseBase.Then(Func onResolved) + { + return Then((x) => { onResolved(new PromiseResult(x)); }, null); + } /// /// Add a resolved callback. @@ -364,16 +364,16 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Action onResolved) - { - return Then((x) => { onResolved(new PromiseResult(x)); }, null); - } + IPromiseBase IPromiseBase.Then(Action onResolved) + { + return Then((x) => { onResolved(new PromiseResult(x)); }, null); + } - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - public IPromise Then(Func> onResolved, Action onRejected) + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + public IPromise Then(Func> onResolved, Action onRejected) { // This version of the function must supply an onResolved. // Otherwise there is now way to get the converted value to pass to the resulting promise. @@ -447,15 +447,15 @@ public IPromise Then(Func onResolved, Action onR return resultPromise; } - IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) - { - return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); - } + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + { + return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); + } - /// - /// Add a resolved callback and a rejected callback. - /// - public IPromise Then(Action onResolved, Action onRejected) + /// + /// Add a resolved callback and a rejected callback. + /// + public IPromise Then(Action onResolved, Action onRejected) { var resultPromise = new Promise(); resultPromise.WithName(Name); @@ -485,16 +485,16 @@ public IPromise Then(Action onResolved, Action return resultPromise; } - IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) - { - return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); - } + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + { + return Then((x) => { onResolved(new PromiseResult(x)); }, onRejected); + } - /// - /// Return a new promise with a different value. - /// May also change the type of the value. - /// - public IPromise Then(Func transform) + /// + /// Return a new promise with a different value. + /// May also change the type of the value. + /// + public IPromise Then(Func transform) { // Argument.NotNull(() => transform); return Then(value => Promise.Resolved(transform(value))); @@ -553,10 +553,10 @@ public IPromise ThenAll(Func> chain) return Then(value => Promise.All(chain(value))); } - IPromiseBase IPromiseBase.ThenAll(Func> chain) - { - return ThenAll((x) => { return chain(); }); - } + IPromiseBase IPromiseBase.ThenAll(Func> chain) + { + return ThenAll((x) => { return chain(); }); + } /// /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. diff --git a/Promise_Base.cs b/Promise_Base.cs index 026e9f4..222534d 100644 --- a/Promise_Base.cs +++ b/Promise_Base.cs @@ -4,271 +4,271 @@ namespace RSG { - public interface IPromiseBase - { - /// - /// Set the name of the promise, useful for debugging. - /// - IPromiseBase WithName(string name); - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// onRejected is called on error. - /// - void Done(Action onResolved, Action onRejected); - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// Adds a default error handler. - /// - void Done(Action onResolved); - - /// - /// Complete the promise. Adds a default error handler. - /// - void Done(); - - /// - /// Handle errors for the promise. - /// - IPromiseBase Catch(Action onRejected); - - /// - /// Add a resolved callback that chains a non-value promise. - /// - IPromiseBase Then(Func onResolved); - - /// - /// Add a resolved callback. - /// - IPromiseBase Then(Action onResolved); - - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a non-value promise. - /// - IPromiseBase Then(Func onResolved, Action onRejected); - - /// - /// Add a resolved callback and a rejected callback. - /// - IPromiseBase Then(Action onResolved, Action onRejected); - - /// - /// Chain an enumerable of promises, all of which must resolve. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromiseBase ThenAll(Func> chain); - } - - /// - /// Interface for a promise that can be rejected. - /// - public interface IRejectable - { - /// - /// Reject the promise with an exception. - /// - void Reject(Exception ex); - } - - /// - /// Arguments to the UnhandledError event. - /// - public class ExceptionEventArgs : EventArgs - { - internal ExceptionEventArgs(Exception exception) - { - // Argument.NotNull(() => exception); - - this.Exception = exception; - } - - public Exception Exception - { - get; - private set; - } - } - - /// - /// Represents a handler invoked when the promise is rejected. - /// - public struct RejectHandler - { - /// - /// Callback fn. - /// - public Action callback; - - /// - /// The promise that is rejected when there is an error while invoking the handler. - /// - public IRejectable rejectable; - } - - public class PromiseResult - { - public static readonly PromiseResult None = new PromiseResult(); - - public readonly bool hasValue; - public readonly object Result; - - public PromiseResult() - { - hasValue = false; - } - - public PromiseResult(object value) - { - hasValue = true; - Result = value; - } - } - - /// - /// Specifies the state of a promise. - /// - public enum PromiseState - { - Pending, // The promise is in-flight. - Rejected, // The promise has been rejected. - Resolved // The promise has been resolved. - }; - - /// - /// Used to list information of pending promises. - /// - public interface IPromiseInfo - { - /// - /// Id of the promise. - /// - int Id { get; } - - /// - /// Human-readable name for the promise. - /// - string Name { get; } - } - - public abstract class Promise_Base : IPromiseInfo - { - /// - /// The exception when the promise is rejected. - /// - protected Exception rejectionException; - - /// - /// Error handlers. - /// - protected List rejectHandlers; - - /// - /// ID of the promise, useful for debugging. - /// - public int Id { get; protected set; } - - /// - /// Name of the promise, when set, useful for debugging. - /// - public string Name { get; protected set; } - - /// - /// Tracks the current state of the promise. - /// - public PromiseState CurState { get; protected set; } - - public Promise_Base() - { - this.CurState = PromiseState.Pending; - this.Id = ++Promise.nextPromiseId; - - if (Promise.EnablePromiseTracking) - { - Promise.pendingPromises.Add(this); - } - } - - /// - /// Add a rejection handler for this promise. - /// - protected void AddRejectHandler(Action onRejected, IRejectable rejectable) - { - if (rejectHandlers == null) - { - rejectHandlers = new List(); - } - - rejectHandlers.Add(new RejectHandler() - { - callback = onRejected, - rejectable = rejectable - }); - } - - /// - /// Invoke a single handler. - /// - protected void InvokeHandler(Action callback, IRejectable rejectable, T value) - { - // Argument.NotNull(() => callback); - // Argument.NotNull(() => rejectable); - - try - { - callback(value); - } - catch (Exception ex) - { - rejectable.Reject(ex); - } - } - - protected virtual void ClearHandlers() - { - rejectHandlers = null; - } - - /// - /// Invoke all reject handlers. - /// - protected void InvokeRejectHandlers(Exception ex) - { - // Argument.NotNull(() => ex); - - if (rejectHandlers != null) - { - rejectHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, ex)); - } - - ClearHandlers(); - } - - /// - /// Reject the promise with an exception. - /// - public void Reject(Exception ex) - { - // Argument.NotNull(() => ex); - - if (CurState != PromiseState.Pending) - { - throw new ApplicationException("Attempt to reject a promise that is already in state: " + CurState + ", a promise can only be rejected when it is still in state: " + PromiseState.Pending); - } - - rejectionException = ex; - CurState = PromiseState.Rejected; - - if (Promise.EnablePromiseTracking) - { - Promise.pendingPromises.Remove(this); - } - - InvokeRejectHandlers(ex); - } - } + public interface IPromiseBase + { + /// + /// Set the name of the promise, useful for debugging. + /// + IPromiseBase WithName(string name); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void Done(Action onResolved, Action onRejected); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void Done(Action onResolved); + + /// + /// Complete the promise. Adds a default error handler. + /// + void Done(); + + /// + /// Handle errors for the promise. + /// + IPromiseBase Catch(Action onRejected); + + /// + /// Add a resolved callback that chains a non-value promise. + /// + IPromiseBase Then(Func onResolved); + + /// + /// Add a resolved callback. + /// + IPromiseBase Then(Action onResolved); + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + IPromiseBase Then(Func onResolved, Action onRejected); + + /// + /// Add a resolved callback and a rejected callback. + /// + IPromiseBase Then(Action onResolved, Action onRejected); + + /// + /// Chain an enumerable of promises, all of which must resolve. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromiseBase ThenAll(Func> chain); + } + + /// + /// Interface for a promise that can be rejected. + /// + public interface IRejectable + { + /// + /// Reject the promise with an exception. + /// + void Reject(Exception ex); + } + + /// + /// Arguments to the UnhandledError event. + /// + public class ExceptionEventArgs : EventArgs + { + internal ExceptionEventArgs(Exception exception) + { + // Argument.NotNull(() => exception); + + this.Exception = exception; + } + + public Exception Exception + { + get; + private set; + } + } + + /// + /// Represents a handler invoked when the promise is rejected. + /// + public struct RejectHandler + { + /// + /// Callback fn. + /// + public Action callback; + + /// + /// The promise that is rejected when there is an error while invoking the handler. + /// + public IRejectable rejectable; + } + + public class PromiseResult + { + public static readonly PromiseResult None = new PromiseResult(); + + public readonly bool hasValue; + public readonly object Result; + + public PromiseResult() + { + hasValue = false; + } + + public PromiseResult(object value) + { + hasValue = true; + Result = value; + } + } + + /// + /// Specifies the state of a promise. + /// + public enum PromiseState + { + Pending, // The promise is in-flight. + Rejected, // The promise has been rejected. + Resolved // The promise has been resolved. + }; + + /// + /// Used to list information of pending promises. + /// + public interface IPromiseInfo + { + /// + /// Id of the promise. + /// + int Id { get; } + + /// + /// Human-readable name for the promise. + /// + string Name { get; } + } + + public abstract class Promise_Base : IPromiseInfo + { + /// + /// The exception when the promise is rejected. + /// + protected Exception rejectionException; + + /// + /// Error handlers. + /// + protected List rejectHandlers; + + /// + /// ID of the promise, useful for debugging. + /// + public int Id { get; protected set; } + + /// + /// Name of the promise, when set, useful for debugging. + /// + public string Name { get; protected set; } + + /// + /// Tracks the current state of the promise. + /// + public PromiseState CurState { get; protected set; } + + public Promise_Base() + { + this.CurState = PromiseState.Pending; + this.Id = ++Promise.nextPromiseId; + + if (Promise.EnablePromiseTracking) + { + Promise.pendingPromises.Add(this); + } + } + + /// + /// Add a rejection handler for this promise. + /// + protected void AddRejectHandler(Action onRejected, IRejectable rejectable) + { + if (rejectHandlers == null) + { + rejectHandlers = new List(); + } + + rejectHandlers.Add(new RejectHandler() + { + callback = onRejected, + rejectable = rejectable + }); + } + + /// + /// Invoke a single handler. + /// + protected void InvokeHandler(Action callback, IRejectable rejectable, T value) + { + // Argument.NotNull(() => callback); + // Argument.NotNull(() => rejectable); + + try + { + callback(value); + } + catch (Exception ex) + { + rejectable.Reject(ex); + } + } + + protected virtual void ClearHandlers() + { + rejectHandlers = null; + } + + /// + /// Invoke all reject handlers. + /// + protected void InvokeRejectHandlers(Exception ex) + { + // Argument.NotNull(() => ex); + + if (rejectHandlers != null) + { + rejectHandlers.Each(handler => InvokeHandler(handler.callback, handler.rejectable, ex)); + } + + ClearHandlers(); + } + + /// + /// Reject the promise with an exception. + /// + public void Reject(Exception ex) + { + // Argument.NotNull(() => ex); + + if (CurState != PromiseState.Pending) + { + throw new ApplicationException("Attempt to reject a promise that is already in state: " + CurState + ", a promise can only be rejected when it is still in state: " + PromiseState.Pending); + } + + rejectionException = ex; + CurState = PromiseState.Rejected; + + if (Promise.EnablePromiseTracking) + { + Promise.pendingPromises.Remove(this); + } + + InvokeRejectHandlers(ex); + } + } } diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index 2f625f8..6675c23 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -17,39 +17,39 @@ public interface IPromise : IPromiseBase /// new IPromise WithName(string name); - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// onRejected is called on error. - /// - void Done(Action onResolved, Action onRejected); - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// Adds a default error handler. - /// - void Done(Action onResolved); - - /// - /// Handle errors for the promise. - /// - new IPromise Catch(Action onRejected); + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void Done(Action onResolved, Action onRejected); + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void Done(Action onResolved); + + /// + /// Handle errors for the promise. + /// + new IPromise Catch(Action onRejected); /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). /// IPromise Then(Func> onResolved); - /// - /// Add a resolved callback that chains a non-value promise. - /// - IPromise Then(Func onResolved); + /// + /// Add a resolved callback that chains a non-value promise. + /// + IPromise Then(Func onResolved); - /// - /// Add a resolved callback. - /// - IPromise Then(Action onResolved); + /// + /// Add a resolved callback. + /// + IPromise Then(Action onResolved); /// /// Add a resolved callback and a rejected callback. @@ -57,23 +57,23 @@ public interface IPromise : IPromiseBase /// IPromise Then(Func> onResolved, Action onRejected); - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a non-value promise. - /// - IPromise Then(Func onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + IPromise Then(Func onResolved, Action onRejected); - /// - /// Add a resolved callback and a rejected callback. - /// - IPromise Then(Action onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// + IPromise Then(Action onResolved, Action onRejected); - /// - /// Chain an enumerable of promises, all of which must resolve. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - new IPromise ThenAll(Func> chain); + /// + /// Chain an enumerable of promises, all of which must resolve. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + new IPromise ThenAll(Func> chain); /// /// Chain an enumerable of promises, all of which must resolve. @@ -257,7 +257,7 @@ private void InvokeResolveHandler(Action callback, IRejectable rejectable) /// override protected void ClearHandlers() { - base.ClearHandlers(); + base.ClearHandlers(); resolveHandlers = null; } @@ -320,36 +320,36 @@ public void Done(Action onResolved) ); } - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// onRejected is called on error. - /// - void IPromiseBase.Done(Action onResolved, Action onRejected) - { - Then(() => { onResolved(PromiseResult.None); }, onRejected) - .Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Completes the promise. - /// onResolved is called on successful completion. - /// Adds a default error handler. - /// - void IPromiseBase.Done(Action onResolved) - { - Then(() => { onResolved(PromiseResult.None); }) - .Catch(ex => - Promise.PropagateUnhandledException(this, ex) - ); - } - - /// - /// Complete the promise. Adds a defualt error handler. - /// - public void Done() + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// onRejected is called on error. + /// + void IPromiseBase.Done(Action onResolved, Action onRejected) + { + Then(() => { onResolved(PromiseResult.None); }, onRejected) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Completes the promise. + /// onResolved is called on successful completion. + /// Adds a default error handler. + /// + void IPromiseBase.Done(Action onResolved) + { + Then(() => { onResolved(PromiseResult.None); }) + .Catch(ex => + Promise.PropagateUnhandledException(this, ex) + ); + } + + /// + /// Complete the promise. Adds a defualt error handler. + /// + public void Done() { Catch(ex => Promise.PropagateUnhandledException(this, ex) @@ -365,10 +365,10 @@ public IPromise WithName(string name) return this; } - IPromiseBase IPromiseBase.WithName(string name) - { - return WithName(name); - } + IPromiseBase IPromiseBase.WithName(string name) + { + return WithName(name); + } /// /// Handle errors for the promise. @@ -397,10 +397,10 @@ public IPromise Catch(Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Catch(Action onRejected) - { - return Catch(onRejected); - } + IPromiseBase IPromiseBase.Catch(Action onRejected) + { + return Catch(onRejected); + } /// /// Add a resolved callback that chains a value promise (optionally converting to a different value type). @@ -418,10 +418,10 @@ public IPromise Then(Func onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Func onResolved) - { - return Then(() => { onResolved(PromiseResult.None); }); - } + IPromiseBase IPromiseBase.Then(Func onResolved) + { + return Then(() => { onResolved(PromiseResult.None); }); + } /// /// Add a resolved callback. @@ -431,16 +431,16 @@ public IPromise Then(Action onResolved) return Then(onResolved, null); } - IPromiseBase IPromiseBase.Then(Action onResolved) - { - return Then(() => { onResolved(PromiseResult.None); }); - } + IPromiseBase IPromiseBase.Then(Action onResolved) + { + return Then(() => { onResolved(PromiseResult.None); }); + } - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - public IPromise Then(Func> onResolved, Action onRejected) + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + public IPromise Then(Func> onResolved, Action onRejected) { // This version of the function must supply an onResolved. // Otherwise there is now way to get the converted value to pass to the resulting promise. @@ -514,10 +514,10 @@ public IPromise Then(Func onResolved, Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) - { - return Then(() => { onResolved(PromiseResult.None); }, onRejected); - } + IPromiseBase IPromiseBase.Then(Func onResolved, Action onRejected) + { + return Then(() => { onResolved(PromiseResult.None); }, onRejected); + } /// /// Add a resolved callback and a rejected callback. @@ -552,15 +552,15 @@ public IPromise Then(Action onResolved, Action onRejected) return resultPromise; } - IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) - { - return Then(() => { onResolved(PromiseResult.None); }, onRejected); - } + IPromiseBase IPromiseBase.Then(Action onResolved, Action onRejected) + { + return Then(() => { onResolved(PromiseResult.None); }, onRejected); + } - /// - /// Helper function to invoke or register resolve/reject handlers. - /// - private void ActionHandlers(IRejectable resultPromise, Action resolveHandler, Action rejectHandler) + /// + /// Helper function to invoke or register resolve/reject handlers. + /// + private void ActionHandlers(IRejectable resultPromise, Action resolveHandler, Action rejectHandler) { if (CurState == PromiseState.Resolved) { @@ -587,10 +587,10 @@ public IPromise ThenAll(Func> chain) return Then(() => Promise.All(chain())); } - IPromiseBase IPromiseBase.ThenAll(Func> chain) - { - return ThenAll(chain); - } + IPromiseBase IPromiseBase.ThenAll(Func> chain) + { + return ThenAll(chain); + } /// /// Chain an enumerable of promises, all of which must resolve. From 7630853bed624e569b52677dd3b6d61716045b99 Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Fri, 24 Jun 2016 12:03:46 -0700 Subject: [PATCH 07/10] Implement Finally #9 --- Promise.cs | 45 ++++++++++++++- Promise_Base.cs | 8 ++- Promise_NonGeneric.cs | 45 ++++++++++++++- Tests/PromiseTests.cs | 95 +++++++++++++++++++++++++++++++ Tests/Promise_NonGeneric_Tests.cs | 95 +++++++++++++++++++++++++++++++ 5 files changed, 283 insertions(+), 5 deletions(-) diff --git a/Promise.cs b/Promise.cs index ac7f699..34d8674 100644 --- a/Promise.cs +++ b/Promise.cs @@ -111,7 +111,19 @@ public interface IPromise: IPromiseBase /// Yields the value from the first promise that has resolved. /// IPromise ThenRace(Func> chain); - } + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + new IPromise Finally(Action onComplete); + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromise Finally(Func> onComplete); + } /// /// Interface for a promise that can be rejected or resolved. @@ -702,5 +714,34 @@ public static IPromise Rejected(Exception ex) promise.Reject(ex); return promise; } - } + + public IPromise Finally(Action onComplete) + { + Promise promise = new Promise(); + + Promise.Race( + this.Then((x) => { promise.Resolve(); }), + this.Catch((e) => { promise.Resolve(); }) + ); + + return promise.Then(onComplete); + } + + public IPromise Finally(Func> onComplete) + { + Promise promise = new Promise(); + + Promise.Race( + this.Then((x) => { promise.Resolve(); }), + this.Catch((e) => { promise.Resolve(); }) + ); + + return promise.Then(onComplete); + } + + IPromiseBase IPromiseBase.Finally(Action onComplete) + { + return Finally(onComplete); + } + } } \ No newline at end of file diff --git a/Promise_Base.cs b/Promise_Base.cs index 222534d..e763c04 100644 --- a/Promise_Base.cs +++ b/Promise_Base.cs @@ -62,7 +62,13 @@ public interface IPromiseBase /// It is rejected as soon as any of the promises have been rejected. /// IPromiseBase ThenAll(Func> chain); - } + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromiseBase Finally(Action onComplete); + } /// /// Interface for a promise that can be rejected. diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index 6675c23..4dfda97 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -103,7 +103,19 @@ public interface IPromise : IPromiseBase /// Returns a promise that resolves when the first of the promises has resolved. /// IPromise ThenRace(Func>> chain); - } + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + new IPromise Finally(Action onComplete); + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromise Finally(Func> onComplete); + } /// /// Interface for a promise that can be rejected or resolved. @@ -788,5 +800,34 @@ internal static void PropagateUnhandledException(object sender, Exception ex) unhandlerException(sender, new ExceptionEventArgs(ex)); } } - } + + public IPromise Finally(Action onComplete) + { + Promise promise = new Promise(); + + Promise.Race( + this.Then(() => { promise.Resolve(); }), + this.Catch((e) => { promise.Resolve(); }) + ); + + return promise.Then(onComplete); + } + + public IPromise Finally(Func> onComplete) + { + Promise promise = new Promise(); + + Promise.Race( + this.Then(() => { promise.Resolve(); }), + this.Catch((e) => { promise.Resolve(); }) + ); + + return promise.Then(() => { return onComplete(); }); + } + + IPromiseBase IPromiseBase.Finally(Action onComplete) + { + return Finally(onComplete); + } + } } \ No newline at end of file diff --git a/Tests/PromiseTests.cs b/Tests/PromiseTests.cs index 2847516..c867f71 100644 --- a/Tests/PromiseTests.cs +++ b/Tests/PromiseTests.cs @@ -986,5 +986,100 @@ public void exception_during_Then_onResolved_triggers_error_hander() Assert.Equal(0, callback); Assert.Equal(1, errorCallback); } + + [Fact] + public void finally_is_called_after_resolve() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }).Then((x) => { }); + + promise.Resolve(0); + + Assert.Equal(1, callback); + } + + [Fact] + public void finally_is_called_after_reject() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }); + + promise.Reject(new Exception()); + + Assert.Equal(1, callback); + } + + [Fact] + public void resolved_chain_continues_after_finally() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }) + .Then(() => + { + ++callback; + }); + + promise.Resolve(0); + + Assert.Equal(2, callback); + } + + [Fact] + public void rejected_chain_continues_after_finally() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }) + .Then(() => + { + ++callback; + }); + + promise.Reject(new Exception()); + + Assert.Equal(2, callback); + } + + [Fact] + public void can_chain_promise_after_finally() + { + var promise = new Promise(); + var expectedValue = 5; + var callback = 0; + + promise.Finally(() => + { + ++callback; + return Promise.Resolved(expectedValue); + }) + .Then((x) => + { + ++callback; + Assert.Equal(expectedValue, x); + }); + + promise.Resolve(0); + + Assert.Equal(2, callback); + } } } diff --git a/Tests/Promise_NonGeneric_Tests.cs b/Tests/Promise_NonGeneric_Tests.cs index 600fa55..46309bb 100644 --- a/Tests/Promise_NonGeneric_Tests.cs +++ b/Tests/Promise_NonGeneric_Tests.cs @@ -1110,5 +1110,100 @@ public void inner_exception_handled_by_outer_promise_with_results() Promise.UnhandledException -= handler; } } + + [Fact] + public void finally_is_called_after_resolve() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }); + + promise.Resolve(); + + Assert.Equal(1, callback); + } + + [Fact] + public void finally_is_called_after_reject() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }); + + promise.Reject(new Exception()); + + Assert.Equal(1, callback); + } + + [Fact] + public void resolved_chain_continues_after_finally() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }) + .Then(() => + { + ++callback; + }); + + promise.Resolve(); + + Assert.Equal(2, callback); + } + + [Fact] + public void rejected_chain_continues_after_finally() + { + var promise = new Promise(); + var callback = 0; + + promise.Finally(() => + { + ++callback; + }) + .Then(() => + { + ++callback; + }); + + promise.Reject(new Exception()); + + Assert.Equal(2, callback); + } + + [Fact] + public void can_chain_promise_after_finally() + { + var promise = new Promise(); + var expectedValue = 5; + var callback = 0; + + promise.Finally(() => + { + ++callback; + return Promise.Resolved(expectedValue); + }) + .Then((x) => + { + ++callback; + Assert.Equal(expectedValue, x); + }); + + promise.Resolve(); + + Assert.Equal(2, callback); + } } } From 74c5ed1e557adf75af7e32feb03e4112a0163c5c Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Fri, 24 Jun 2016 12:30:13 -0700 Subject: [PATCH 08/10] Preserve promise name accross Finally() --- Promise.cs | 2 ++ Promise_NonGeneric.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Promise.cs b/Promise.cs index 34d8674..def2662 100644 --- a/Promise.cs +++ b/Promise.cs @@ -718,6 +718,7 @@ public static IPromise Rejected(Exception ex) public IPromise Finally(Action onComplete) { Promise promise = new Promise(); + promise.WithName(Name); Promise.Race( this.Then((x) => { promise.Resolve(); }), @@ -730,6 +731,7 @@ public IPromise Finally(Action onComplete) public IPromise Finally(Func> onComplete) { Promise promise = new Promise(); + promise.WithName(Name); Promise.Race( this.Then((x) => { promise.Resolve(); }), diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index 4dfda97..264af39 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -804,6 +804,7 @@ internal static void PropagateUnhandledException(object sender, Exception ex) public IPromise Finally(Action onComplete) { Promise promise = new Promise(); + promise.WithName(Name); Promise.Race( this.Then(() => { promise.Resolve(); }), @@ -816,6 +817,7 @@ public IPromise Finally(Action onComplete) public IPromise Finally(Func> onComplete) { Promise promise = new Promise(); + promise.WithName(Name); Promise.Race( this.Then(() => { promise.Resolve(); }), From 9614c2c23e785c5b82f11b0632088cef0f1e87d2 Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Fri, 24 Jun 2016 13:22:26 -0700 Subject: [PATCH 09/10] Remove race from Finally. It was an artifact of a previous approach. --- Promise.cs | 12 ++++-------- Promise_NonGeneric.cs | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Promise.cs b/Promise.cs index def2662..270d2ae 100644 --- a/Promise.cs +++ b/Promise.cs @@ -720,10 +720,8 @@ public IPromise Finally(Action onComplete) Promise promise = new Promise(); promise.WithName(Name); - Promise.Race( - this.Then((x) => { promise.Resolve(); }), - this.Catch((e) => { promise.Resolve(); }) - ); + this.Then((x) => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); return promise.Then(onComplete); } @@ -733,10 +731,8 @@ public IPromise Finally(Func> onCom Promise promise = new Promise(); promise.WithName(Name); - Promise.Race( - this.Then((x) => { promise.Resolve(); }), - this.Catch((e) => { promise.Resolve(); }) - ); + this.Then((x) => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); return promise.Then(onComplete); } diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index 264af39..d4321e0 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -806,10 +806,8 @@ public IPromise Finally(Action onComplete) Promise promise = new Promise(); promise.WithName(Name); - Promise.Race( - this.Then(() => { promise.Resolve(); }), - this.Catch((e) => { promise.Resolve(); }) - ); + this.Then(() => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); return promise.Then(onComplete); } @@ -819,10 +817,8 @@ public IPromise Finally(Func> onCom Promise promise = new Promise(); promise.WithName(Name); - Promise.Race( - this.Then(() => { promise.Resolve(); }), - this.Catch((e) => { promise.Resolve(); }) - ); + this.Then(() => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); return promise.Then(() => { return onComplete(); }); } From a2538b21908e5d468a2c2a74dd608d3a71ea1011 Mon Sep 17 00:00:00 2001 From: Nathan Loewen Date: Fri, 24 Jun 2016 13:25:12 -0700 Subject: [PATCH 10/10] Spaces -> Tabs --- Promise.cs | 68 +++++++++++++++++++++---------------------- Promise_Base.cs | 12 ++++---- Promise_NonGeneric.cs | 66 ++++++++++++++++++++--------------------- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/Promise.cs b/Promise.cs index 270d2ae..8f5f3e0 100644 --- a/Promise.cs +++ b/Promise.cs @@ -112,18 +112,18 @@ public interface IPromise: IPromiseBase /// IPromise ThenRace(Func> chain); - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// - new IPromise Finally(Action onComplete); - - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// - IPromise Finally(Func> onComplete); - } + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + new IPromise Finally(Action onComplete); + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromise Finally(Func> onComplete); + } /// /// Interface for a promise that can be rejected or resolved. @@ -715,31 +715,31 @@ public static IPromise Rejected(Exception ex) return promise; } - public IPromise Finally(Action onComplete) - { - Promise promise = new Promise(); - promise.WithName(Name); + public IPromise Finally(Action onComplete) + { + Promise promise = new Promise(); + promise.WithName(Name); - this.Then((x) => { promise.Resolve(); }); - this.Catch((e) => { promise.Resolve(); }); - - return promise.Then(onComplete); - } + this.Then((x) => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); + + return promise.Then(onComplete); + } - public IPromise Finally(Func> onComplete) - { - Promise promise = new Promise(); - promise.WithName(Name); + public IPromise Finally(Func> onComplete) + { + Promise promise = new Promise(); + promise.WithName(Name); - this.Then((x) => { promise.Resolve(); }); - this.Catch((e) => { promise.Resolve(); }); + this.Then((x) => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); - return promise.Then(onComplete); - } + return promise.Then(onComplete); + } - IPromiseBase IPromiseBase.Finally(Action onComplete) - { - return Finally(onComplete); - } - } + IPromiseBase IPromiseBase.Finally(Action onComplete) + { + return Finally(onComplete); + } + } } \ No newline at end of file diff --git a/Promise_Base.cs b/Promise_Base.cs index e763c04..1f82478 100644 --- a/Promise_Base.cs +++ b/Promise_Base.cs @@ -63,12 +63,12 @@ public interface IPromiseBase /// IPromiseBase ThenAll(Func> chain); - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// - IPromiseBase Finally(Action onComplete); - } + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromiseBase Finally(Action onComplete); + } /// /// Interface for a promise that can be rejected. diff --git a/Promise_NonGeneric.cs b/Promise_NonGeneric.cs index d4321e0..f0264d1 100644 --- a/Promise_NonGeneric.cs +++ b/Promise_NonGeneric.cs @@ -104,18 +104,18 @@ public interface IPromise : IPromiseBase /// IPromise ThenRace(Func>> chain); - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// - new IPromise Finally(Action onComplete); - - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// - IPromise Finally(Func> onComplete); - } + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + new IPromise Finally(Action onComplete); + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// + IPromise Finally(Func> onComplete); + } /// /// Interface for a promise that can be rejected or resolved. @@ -801,31 +801,31 @@ internal static void PropagateUnhandledException(object sender, Exception ex) } } - public IPromise Finally(Action onComplete) - { - Promise promise = new Promise(); - promise.WithName(Name); + public IPromise Finally(Action onComplete) + { + Promise promise = new Promise(); + promise.WithName(Name); - this.Then(() => { promise.Resolve(); }); - this.Catch((e) => { promise.Resolve(); }); + this.Then(() => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); - return promise.Then(onComplete); - } + return promise.Then(onComplete); + } - public IPromise Finally(Func> onComplete) - { - Promise promise = new Promise(); - promise.WithName(Name); + public IPromise Finally(Func> onComplete) + { + Promise promise = new Promise(); + promise.WithName(Name); - this.Then(() => { promise.Resolve(); }); - this.Catch((e) => { promise.Resolve(); }); + this.Then(() => { promise.Resolve(); }); + this.Catch((e) => { promise.Resolve(); }); - return promise.Then(() => { return onComplete(); }); - } + return promise.Then(() => { return onComplete(); }); + } - IPromiseBase IPromiseBase.Finally(Action onComplete) - { - return Finally(onComplete); - } - } + IPromiseBase IPromiseBase.Finally(Action onComplete) + { + return Finally(onComplete); + } + } } \ No newline at end of file