Mercurial > pub > ImplabNet
changeset 11:6ec82bf68c8e promises
refactoring
author | cin |
---|---|
date | Tue, 05 Nov 2013 01:09:58 +0400 |
parents | aa33d0bb8c0c |
children | eb418ba8275b |
files | Implab.Test/AsyncTests.cs Implab.Test/PromiseHelper.cs Implab.v11.suo Implab/AsyncPool.cs Implab/IPromise.cs Implab/Implab.csproj Implab/Parallels/AsyncPool.cs Implab/Promise.cs |
diffstat | 8 files changed, 178 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- 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<int>(); + + var p2 = p.Error(e => 101); + + p.Reject(new Exception()); + + Assert.AreEqual(p2.Join(), 101); + } + + [TestMethod] public void ChainTest () { var p1 = new Promise<int> ();
--- 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;
--- 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 { - /// <summary> - /// Класс для распаралеливания задач. - /// </summary> - /// <remarks> - /// Используя данный класс и лямда выражения можно распараллелить - /// вычисления, для этого используется концепция обещаний. - /// </remarks> - public static class AsyncPool { - - public static Promise<T> Invoke<T>(Func<T> func) { - var p = new Promise<T>(); - - ThreadPool.QueueUserWorkItem(param => { - try { - p.Resolve(func()); - } catch(Exception e) { - p.Reject(e); - } - }); - - return p; - } - } -}
--- 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 @@ } /// <summary> - /// Tries to cancel the promise or the complete chain. + /// Tries to cancel the the complete chain of promises. /// </summary> - /// <param name="dependencies">Try to cancel the whole promise chain, the parent promise will be cancelled only if it has only one promise</param> - /// <returns></returns> - bool Cancel(bool dependencies); + /// <returns><c>true</c> - if the promise has been cancelled, otherwise the promise will be resolved (or resolved already).</returns> + bool Cancel(); /// <summary> /// Registers handler for the case when the promise is cencelled. If the promise already cancelled the
--- 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 @@ <Compile Include="ProgressInitEventArgs.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Promise.cs" /> - <Compile Include="AsyncPool.cs" /> + <Compile Include="Parallels\AsyncPool.cs" /> <Compile Include="Safe.cs" /> <Compile Include="ValueEventArgs.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <ItemGroup> - <Folder Include="Parallels\" /> - </ItemGroup> + <ItemGroup /> </Project> \ No newline at end of file
--- /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 { + /// <summary> + /// Класс для распаралеливания задач. + /// </summary> + /// <remarks> + /// Используя данный класс и лямда выражения можно распараллелить + /// вычисления, для этого используется концепция обещаний. + /// </remarks> + public static class AsyncPool { + + public static Promise<T> Invoke<T>(Func<T> func) { + var p = new Promise<T>(); + + ThreadPool.QueueUserWorkItem(param => { + try { + p.Resolve(func()); + } catch(Exception e) { + p.Reject(e); + } + }); + + return p; + } + } +}
--- 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<out T>(Exception e); public delegate void ResultHandler<in T>(T result); public delegate TNew ResultMapper<in TSrc, out TNew>(TSrc result); public delegate Promise<TNew> ChainedOperation<in TSrc, TNew>(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; - } - /// <summary> - /// Добавляет обработчики событий выполнения обещания. + /// Adds new handlers to this promise. /// </summary> - /// <param name="success">Обработчик успешного выполнения обещания. - /// Данному обработчику будет передан результат выполнения операции.</param> - /// <param name="error">Обработчик ошибки. Данный обработчик получит - /// исключение возникшее при выполнении операции.</param> - /// <returns>Само обещание</returns> + /// <param name="success">The handler of the successfully completed operation. + /// This handler will recieve an operation result as a parameter.</param> + /// <param name="error">Handles an exception that may occur during the operation.</param> + /// <returns>The new promise chained to this one.</returns> public Promise<T> Then(ResultHandler<T> success, ErrorHandler error) { if (success == null && error == null) return this; - var medium = new Promise<T>(); + var medium = new Promise<T>(this, true); var handlerInfo = new ResultHandlerInfo(); @@ -198,14 +164,99 @@ return medium; } + /// <summary> + /// Adds new handlers to this promise. + /// </summary> + /// <param name="success">The handler of the successfully completed operation. + /// This handler will recieve an operation result as a parameter.</param> + /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param> + /// <returns>The new promise chained to this one.</returns> + public Promise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) { + if (success == null && error == null) + return this; + + var medium = new Promise<T>(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<T> Then(ResultHandler<T> success) { - return Then(success, null); + if (success == null) + return this; + + var medium = new Promise<T>(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<T> Error(ErrorHandler error) { return Then(null, error); } + /// <summary> + /// Handles error and allows to keep the promise. + /// </summary> + /// <remarks> + /// If the specified handler throws an exception, this exception will be used to reject the promise. + /// </remarks> + /// <param name="handler">The error handler which returns the result of the promise.</param> + /// <returns>New promise.</returns> + public Promise<T> Error(ErrorHandler<T> handler) { + if (handler == null) + return this; + + var medium = new Promise<T>(this, true); + + AddHandler(new ResultHandlerInfo { + errorHandler = e => { + try { + medium.Resolve(handler(e)); + } catch (Exception e2) { + medium.Reject(e2); + } + } + }); + + return medium; + } + public Promise<T> 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;