diff --git a/Implab.Fx.Test/Implab.Fx.Test.csproj b/Implab.Fx.Test/Implab.Fx.Test.csproj
--- a/Implab.Fx.Test/Implab.Fx.Test.csproj
+++ b/Implab.Fx.Test/Implab.Fx.Test.csproj
@@ -31,6 +31,23 @@
prompt
4
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
diff --git a/Implab.Fx/Implab.Fx.csproj b/Implab.Fx/Implab.Fx.csproj
--- a/Implab.Fx/Implab.Fx.csproj
+++ b/Implab.Fx/Implab.Fx.csproj
@@ -30,6 +30,23 @@
prompt
4
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
diff --git a/Implab.Test/Implab.Test.csproj b/Implab.Test/Implab.Test.csproj
--- a/Implab.Test/Implab.Test.csproj
+++ b/Implab.Test/Implab.Test.csproj
@@ -31,6 +31,23 @@
prompt
4
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
diff --git a/Implab.sln b/Implab.sln
--- a/Implab.sln
+++ b/Implab.sln
@@ -20,22 +20,40 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
+ Debug 4.5|Any CPU = Debug 4.5|Any CPU
+ Release 4.5|Any CPU = Release 4.5|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+ {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+ {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+ {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
{2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+ {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
+ {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+ {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+ {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+ {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+ {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
diff --git a/Implab/IPromise.cs b/Implab/IPromise.cs
--- a/Implab/IPromise.cs
+++ b/Implab/IPromise.cs
@@ -27,16 +27,26 @@ namespace Implab {
///
bool IsCancelled { get; }
- IPromise Then(Action success,ErrorHandler error);
+ IPromise Then(Action success, ErrorHandler error, Action cancel);
+ IPromise Then(Action success, ErrorHandler error);
IPromise Then(Action success);
+
+ ///
+ /// Добавляет последнй обработчик в цепочку обещаний, не создает промежуточных обещаний.
+ ///
+ /// Success.
+ /// Error.
+ /// Cancel.
+ void Last(Action success, ErrorHandler error, Action cancel);
+ void Last(Action success, ErrorHandler error);
+ void Last(Action success);
+
IPromise Error(ErrorHandler error);
///
/// Обрабатывает либо ошибку, либо результат. Событие отмены не обрабатывается.
///
/// Обработчик.
/// После обработке ошибки, она передается дальше.
- IPromise Anyway(Action handler);
-
///
/// Обрабатывает либо ошибку, либо результат, либо отмену обещания.
///
diff --git a/Implab/IPromiseT.cs b/Implab/IPromiseT.cs
--- a/Implab/IPromiseT.cs
+++ b/Implab/IPromiseT.cs
@@ -3,27 +3,35 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
-namespace Implab
-{
- public interface IPromise: IPromise
- {
+namespace Implab {
+ public interface IPromise: IPromise {
new T Join();
+
new T Join(int timeout);
+ IPromise Then(ResultHandler success, ErrorHandler error, Action cancel);
+
IPromise Then(ResultHandler success, ErrorHandler error);
+
IPromise Then(ResultHandler success);
+
+ void Last(ResultHandler success, ErrorHandler error, Action cancel);
+ void Last(ResultHandler success, ErrorHandler error);
+ void Last(ResultHandler success);
+
IPromise Error(ErrorHandler error);
- IPromise Map(ResultMapper mapper, ErrorHandler error);
- IPromise Map(ResultMapper mapper);
+ IPromise Then(ResultMapper mapper, ErrorHandler error);
+
+ IPromise Then(ResultMapper mapper);
- IPromise Chain(ChainedOperation chained, ErrorHandler error);
- IPromise Chain(ChainedOperation chained);
+ IPromise Then(ChainedOperation chained, ErrorHandler error);
+
+ IPromise Then(ChainedOperation chained);
new IPromise Cancelled(Action handler);
+
new IPromise Finally(Action handler);
- new IPromise Anyway(Action handler);
-
}
}
diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj
--- a/Implab/Implab.csproj
+++ b/Implab/Implab.csproj
@@ -29,6 +29,25 @@
4
false
+
+ true
+ full
+ false
+ bin\Debug
+ TRACE;DEBUG;NET_4_5
+ prompt
+ 4
+ true
+ false
+
+
+ true
+ bin\Release
+ prompt
+ 4
+ false
+ NET_4_5
+
diff --git a/Implab/Parallels/ArrayTraits.cs b/Implab/Parallels/ArrayTraits.cs
--- a/Implab/Parallels/ArrayTraits.cs
+++ b/Implab/Parallels/ArrayTraits.cs
@@ -29,8 +29,7 @@ namespace Implab.Parallels {
m_pending = source.Length;
m_action = action;
- m_promise.Anyway(() => Dispose());
- m_promise.Cancelled(() => Dispose());
+ m_promise.Finally(Dispose);
InitPool();
}
@@ -48,7 +47,7 @@ namespace Implab.Parallels {
protected override bool TryDequeue(out int unit) {
unit = Interlocked.Increment(ref m_next) - 1;
- return unit >= m_source.Length ? false : true;
+ return unit < m_source.Length;
}
protected override void InvokeUnit(int unit) {
@@ -86,8 +85,7 @@ namespace Implab.Parallels {
m_transform = transform;
m_traceContext = TraceContext.Snapshot();
- m_promise.Anyway(() => Dispose());
- m_promise.Cancelled(() => Dispose());
+ m_promise.Finally(Dispose);
InitPool();
}
@@ -157,16 +155,17 @@ namespace Implab.Parallels {
var semaphore = new Semaphore(threads, threads);
+ // Analysis disable AccessToDisposedClosure
AsyncPool.InvokeNewThread(() => {
for (int i = 0; i < source.Length; i++) {
if(promise.IsResolved)
break; // stop processing in case of error or cancellation
var idx = i;
+
semaphore.WaitOne();
try {
var p1 = transform(source[i]);
- p1.Anyway(() => semaphore.Release());
- p1.Cancelled(() => semaphore.Release());
+ p1.Finally(() => semaphore.Release());
p1.Then(
x => {
res[idx] = x;
@@ -187,7 +186,7 @@ namespace Implab.Parallels {
return 0;
});
- return promise.Anyway(() => semaphore.Dispose());
+ return promise.Finally(semaphore.Dispose);
}
}
diff --git a/Implab/Promise.cs b/Implab/Promise.cs
--- a/Implab/Promise.cs
+++ b/Implab/Promise.cs
@@ -225,6 +225,18 @@ namespace Implab {
Cancel();
}
+
+ public IPromise Then(ResultHandler success, ErrorHandler error, Action cancel) {
+ if (success == null && error == null && cancel == null)
+ return this;
+
+ var medium = new Promise(this, true);
+
+ AddHandler(success, error, cancel, medium);
+
+ return medium;
+ }
+
///
/// Adds new handlers to this promise.
///
@@ -243,6 +255,17 @@ namespace Implab {
return medium;
}
+ public IPromise Then(Action success, ErrorHandler error, Action cancel) {
+ return Then(
+ x => success(),
+ e => {
+ error(e);
+ return default(T);
+ },
+ cancel
+ );
+ }
+
public IPromise Then(Action success, ErrorHandler error) {
return Then(
x => success(),
@@ -269,6 +292,39 @@ namespace Implab {
return medium;
}
+ public void Last(ResultHandler success, ErrorHandler error, Action cancel) {
+ if (success == null && error == null && cancel == null)
+ return;
+
+ ErrorHandler errorHandler = null;
+ if (error != null)
+ errorHandler = err => {
+ error(err);
+ return default(T);
+ };
+ AddHandler(success, errorHandler, cancel, null);
+ }
+
+ public void Last(ResultHandler success, ErrorHandler error) {
+ Last(success, error, null);
+ }
+
+ public void Last(ResultHandler success) {
+ Last(success, null, null);
+ }
+
+ public void Last(Action success,ErrorHandler error, Action cancel) {
+ Last(x => success(), error, cancel);
+ }
+
+ public void Last(Action success,ErrorHandler error) {
+ Last(x => success(), error, null);
+ }
+
+ public void Last(Action success) {
+ Last(x => success(), null, null);
+ }
+
public IPromise Error(ErrorHandler error) {
if (error == null)
return this;
@@ -307,25 +363,6 @@ namespace Implab {
return medium;
}
- public IPromise Anyway(Action handler) {
- if (handler == null)
- return this;
-
- var medium = new Promise(this, true);
-
- AddHandler(
- x => handler(),
- e => {
- handler();
- throw new TransientPromiseException(e);
- },
- null,
- medium
- );
-
- return medium;
- }
-
///
/// Позволяет преобразовать результат выполения операции к новому типу.
///
@@ -334,7 +371,7 @@ namespace Implab {
/// Обработчик ошибки. Данный обработчик получит
/// исключение возникшее при выполнении операции.
/// Новое обещание, которое будет выполнено при выполнении исходного обещания.
- public IPromise Map(ResultMapper mapper, ErrorHandler error) {
+ public IPromise Then(ResultMapper mapper, ErrorHandler error) {
if (mapper == null)
throw new ArgumentNullException("mapper");
@@ -370,8 +407,8 @@ namespace Implab {
return chained;
}
- public IPromise Map(ResultMapper mapper) {
- return Map(mapper, null);
+ public IPromise Then(ResultMapper mapper) {
+ return Then(mapper, null);
}
///
@@ -384,7 +421,7 @@ namespace Implab {
/// Обработчик ошибки. Данный обработчик получит
/// исключение возникшее при выполнении текуещй операции.
/// Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.
- public IPromise Chain(ChainedOperation chained, ErrorHandler error) {
+ public IPromise Then(ChainedOperation chained, ErrorHandler error) {
// проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно
// создать посредника, к которому будут подвызяваться следующие обработчики.
@@ -442,8 +479,8 @@ namespace Implab {
return medium;
}
- public IPromise Chain(ChainedOperation chained) {
- return Chain(chained, null);
+ public IPromise Then(ChainedOperation chained) {
+ return Then(chained, null);
}
public IPromise Cancelled(Action handler) {
@@ -478,7 +515,7 @@ namespace Implab {
///
///
public IPromise Cast() {
- return Map(x => (T2)(object)x, null);
+ return Then(x => (T2)(object)x, null);
}
///
@@ -504,8 +541,7 @@ namespace Implab {
/// Результат выполнения обещания
public T Join(int timeout) {
var evt = new ManualResetEvent(false);
- Anyway(() => evt.Set());
- Cancelled(() => evt.Set());
+ Finally(() => evt.Set());
if (!evt.WaitOne(timeout, true))
throw new TimeoutException();
@@ -704,10 +740,6 @@ namespace Implab {
return Error(error);
}
- IPromise IPromise.Anyway(Action handler) {
- return Anyway(handler);
- }
-
IPromise IPromise.Finally(Action handler) {
return Finally(handler);
}
diff --git a/Implab/PromiseExtensions.cs b/Implab/PromiseExtensions.cs
--- a/Implab/PromiseExtensions.cs
+++ b/Implab/PromiseExtensions.cs
@@ -1,8 +1,13 @@
using System.Threading;
+using System;
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
namespace Implab {
public static class PromiseExtensions {
public static IPromise DispatchToCurrentContext(this IPromise that) {
+ Safe.ArgumentNotNull(that, "that");
var context = SynchronizationContext.Current;
if (context == null)
return that;
@@ -20,6 +25,7 @@ namespace Implab {
}
public static IPromise DispatchToContext(this IPromise that, SynchronizationContext context) {
+ Safe.ArgumentNotNull(that, "that");
Safe.ArgumentNotNull(context, "context");
var p = new SyncContextPromise(context, that, true);
@@ -33,6 +39,31 @@ namespace Implab {
);
return p;
}
+
+ public static AsyncCallback AsyncCallback(this Promise that, Func callback) {
+ Safe.ArgumentNotNull(that, "that");
+ Safe.ArgumentNotNull(callback, "callback");
+ return ar => {
+ try {
+ that.Resolve(callback(ar));
+ } catch (Exception err) {
+ that.Reject(err);
+ }
+ };
+ }
+
+ #if NET_4_5
+
+ public static Task GetTask(this IPromise that) {
+ Safe.ArgumentNotNull(that, "that");
+ var tcs = new TaskCompletionSource();
+
+ that.Last(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
+
+ return tcs.Task;
+ }
+
+ #endif
}
}