# HG changeset patch # User cin # Date 1383599398 -14400 # Node ID 6ec82bf68c8ef041e506358eacf67fee6f77263e # Parent aa33d0bb8c0cbb2aca37c657e35aedbfdc896b23 refactoring diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab.Test/AsyncTests.cs --- a/Implab.Test/AsyncTests.cs Sun Nov 03 18:07:38 2013 +0400 +++ b/Implab.Test/AsyncTests.cs Tue Nov 05 01:09:58 2013 +0400 @@ -2,6 +2,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Reflection; using System.Threading; +using Implab.Parallels; namespace Implab.Test { @@ -70,6 +71,17 @@ } [TestMethod] + public void FixErrorTest() { + var p = new Promise(); + + var p2 = p.Error(e => 101); + + p.Reject(new Exception()); + + Assert.AreEqual(p2.Join(), 101); + } + + [TestMethod] public void ChainTest () { var p1 = new Promise (); diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab.Test/PromiseHelper.cs --- a/Implab.Test/PromiseHelper.cs Sun Nov 03 18:07:38 2013 +0400 +++ b/Implab.Test/PromiseHelper.cs Tue Nov 05 01:09:58 2013 +0400 @@ -1,4 +1,5 @@ -using System; +using Implab.Parallels; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab.v11.suo Binary file Implab.v11.suo has changed diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab/AsyncPool.cs --- a/Implab/AsyncPool.cs Sun Nov 03 18:07:38 2013 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -using System; -using System.Threading; - -namespace Implab { - /// - /// Класс для распаралеливания задач. - /// - /// - /// Используя данный класс и лямда выражения можно распараллелить - /// вычисления, для этого используется концепция обещаний. - /// - public static class AsyncPool { - - public static Promise Invoke(Func func) { - var p = new Promise(); - - ThreadPool.QueueUserWorkItem(param => { - try { - p.Resolve(func()); - } catch(Exception e) { - p.Reject(e); - } - }); - - return p; - } - } -} diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab/IPromise.cs --- a/Implab/IPromise.cs Sun Nov 03 18:07:38 2013 +0400 +++ b/Implab/IPromise.cs Tue Nov 05 01:09:58 2013 +0400 @@ -24,11 +24,10 @@ } /// - /// Tries to cancel the promise or the complete chain. + /// Tries to cancel the the complete chain of promises. /// - /// Try to cancel the whole promise chain, the parent promise will be cancelled only if it has only one promise - /// - bool Cancel(bool dependencies); + /// true - if the promise has been cancelled, otherwise the promise will be resolved (or resolved already). + bool Cancel(); /// /// Registers handler for the case when the promise is cencelled. If the promise already cancelled the diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab/Implab.csproj --- a/Implab/Implab.csproj Sun Nov 03 18:07:38 2013 +0400 +++ b/Implab/Implab.csproj Tue Nov 05 01:09:58 2013 +0400 @@ -38,12 +38,10 @@ - + - - - + \ No newline at end of file diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab/Parallels/AsyncPool.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Parallels/AsyncPool.cs Tue Nov 05 01:09:58 2013 +0400 @@ -0,0 +1,28 @@ +using System; +using System.Threading; + +namespace Implab.Parallels { + /// + /// Класс для распаралеливания задач. + /// + /// + /// Используя данный класс и лямда выражения можно распараллелить + /// вычисления, для этого используется концепция обещаний. + /// + public static class AsyncPool { + + public static Promise Invoke(Func func) { + var p = new Promise(); + + ThreadPool.QueueUserWorkItem(param => { + try { + p.Resolve(func()); + } catch(Exception e) { + p.Reject(e); + } + }); + + return p; + } + } +} diff -r aa33d0bb8c0c -r 6ec82bf68c8e Implab/Promise.cs --- a/Implab/Promise.cs Sun Nov 03 18:07:38 2013 +0400 +++ b/Implab/Promise.cs Tue Nov 05 01:09:58 2013 +0400 @@ -7,7 +7,7 @@ namespace Implab { public delegate void ErrorHandler(Exception e); - + public delegate T ErrorHandler(Exception e); public delegate void ResultHandler(T result); public delegate TNew ResultMapper(TSrc result); public delegate Promise ChainedOperation(TSrc result); @@ -126,52 +126,18 @@ return Cancel(true); } - protected virtual void OnStateChanged() { - switch (m_state) { - case PromiseState.Resolved: - foreach (var resultHandlerInfo in m_resultHandlers) - try { - if (resultHandlerInfo.resultHandler != null) - resultHandlerInfo.resultHandler(m_result); - } catch (Exception e) { - try { - if (resultHandlerInfo.errorHandler != null) - resultHandlerInfo.errorHandler(e); - } catch { } - } - break; - case PromiseState.Cancelled: - foreach (var cancelHandler in m_cancelHandlers) - cancelHandler(); - break; - case PromiseState.Rejected: - foreach (var resultHandlerInfo in m_resultHandlers) - try { - if (resultHandlerInfo.errorHandler != null) - resultHandlerInfo.errorHandler(m_error); - } catch { } - break; - default: - throw new InvalidOperationException(String.Format("Promise entered an invalid state {0}", m_state)); - } - - m_resultHandlers = null; - m_cancelHandlers = null; - } - /// - /// Добавляет обработчики событий выполнения обещания. + /// Adds new handlers to this promise. /// - /// Обработчик успешного выполнения обещания. - /// Данному обработчику будет передан результат выполнения операции. - /// Обработчик ошибки. Данный обработчик получит - /// исключение возникшее при выполнении операции. - /// Само обещание + /// The handler of the successfully completed operation. + /// This handler will recieve an operation result as a parameter. + /// Handles an exception that may occur during the operation. + /// The new promise chained to this one. public Promise Then(ResultHandler success, ErrorHandler error) { if (success == null && error == null) return this; - var medium = new Promise(); + var medium = new Promise(this, true); var handlerInfo = new ResultHandlerInfo(); @@ -198,14 +164,99 @@ return medium; } + /// + /// Adds new handlers to this promise. + /// + /// The handler of the successfully completed operation. + /// This handler will recieve an operation result as a parameter. + /// Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation. + /// The new promise chained to this one. + public Promise Then(ResultHandler success, ErrorHandler error) { + if (success == null && error == null) + return this; + + var medium = new Promise(this, true); + + var handlerInfo = new ResultHandlerInfo(); + + if (success != null) + handlerInfo.resultHandler = x => { + success(x); + medium.Resolve(x); + }; + else + handlerInfo.resultHandler = medium.Resolve; + + if (error != null) + handlerInfo.errorHandler = x => { + try { + medium.Resolve(error(x)); + } catch { } + medium.Reject(x); + }; + else + handlerInfo.errorHandler = medium.Reject; + + AddHandler(handlerInfo); + + return medium; + } + + public Promise Then(ResultHandler success) { - return Then(success, null); + if (success == null) + return this; + + var medium = new Promise(this, true); + + var handlerInfo = new ResultHandlerInfo(); + + if (success != null) + handlerInfo.resultHandler = x => { + success(x); + medium.Resolve(x); + }; + else + handlerInfo.resultHandler = medium.Resolve; + + handlerInfo.errorHandler = medium.Reject; + + AddHandler(handlerInfo); + + return medium; } public Promise Error(ErrorHandler error) { return Then(null, error); } + /// + /// Handles error and allows to keep the promise. + /// + /// + /// If the specified handler throws an exception, this exception will be used to reject the promise. + /// + /// The error handler which returns the result of the promise. + /// New promise. + public Promise Error(ErrorHandler handler) { + if (handler == null) + return this; + + var medium = new Promise(this, true); + + AddHandler(new ResultHandlerInfo { + errorHandler = e => { + try { + medium.Resolve(handler(e)); + } catch (Exception e2) { + medium.Reject(e2); + } + } + }); + + return medium; + } + public Promise Anyway(Action handler) { if (handler == null) return this; @@ -295,9 +346,9 @@ // notify chained operation that it's not needed medium.Cancelled(() => promise.Cancel()); promise.Then( - medium.Resolve, - medium.Reject - ); + x => medium.Resolve(x), + e => medium.Reject(e) + ); }, errorHandler = delegate(Exception e) { if (error != null) @@ -416,6 +467,39 @@ } } + protected virtual void OnStateChanged() { + switch (m_state) { + case PromiseState.Resolved: + foreach (var resultHandlerInfo in m_resultHandlers) + try { + if (resultHandlerInfo.resultHandler != null) + resultHandlerInfo.resultHandler(m_result); + } catch (Exception e) { + try { + if (resultHandlerInfo.errorHandler != null) + resultHandlerInfo.errorHandler(e); + } catch { } + } + break; + case PromiseState.Cancelled: + foreach (var cancelHandler in m_cancelHandlers) + cancelHandler(); + break; + case PromiseState.Rejected: + foreach (var resultHandlerInfo in m_resultHandlers) + try { + if (resultHandlerInfo.errorHandler != null) + resultHandlerInfo.errorHandler(m_error); + } catch { } + break; + default: + throw new InvalidOperationException(String.Format("Promise entered an invalid state {0}", m_state)); + } + + m_resultHandlers = null; + m_cancelHandlers = null; + } + public bool IsExclusive { @@ -434,7 +518,7 @@ } } - public bool Cancel(bool dependencies) { + protected bool Cancel(bool dependencies) { bool result; lock (m_lock) { @@ -450,7 +534,7 @@ OnStateChanged(); if (dependencies && m_parent != null && m_parent.IsExclusive) { - m_parent.Cancel(true); + m_parent.Cancel(); } return result;