comparison Implab/Promise.cs @ 101:279e226dffdd v2

code cleanup added EnsureDispatched extension
author cin
date Thu, 06 Nov 2014 20:03:19 +0300
parents 8ddf1648eca4
children 5f10d54b45df
comparison
equal deleted inserted replaced
100:673947ce458a 101:279e226dffdd
1 using System; 1 using System;
2 using System.Collections.Generic; 2 using System.Collections.Generic;
3 using System.Reflection; 3 using System.Reflection;
4 using System.Diagnostics;
5 using System.Threading; 4 using System.Threading;
6 using Implab.Parallels; 5 using Implab.Parallels;
7 6
8 namespace Implab { 7 namespace Implab {
9
10 public delegate void ErrorHandler(Exception e);
11 public delegate T ErrorHandler<out T>(Exception e);
12 public delegate void ResultHandler<in T>(T result);
13 public delegate TNew ResultMapper<in TSrc,out TNew>(TSrc result);
14 8
15 /// <summary> 9 /// <summary>
16 /// Класс для асинхронного получения результатов. Так называемое "обещание". 10 /// Класс для асинхронного получения результатов. Так называемое "обещание".
17 /// </summary> 11 /// </summary>
18 /// <typeparam name="T">Тип получаемого результата</typeparam> 12 /// <typeparam name="T">Тип получаемого результата</typeparam>
47 /// </para> 41 /// </para>
48 /// </remarks> 42 /// </remarks>
49 public class Promise<T> : IPromise<T> { 43 public class Promise<T> : IPromise<T> {
50 44
51 protected struct HandlerDescriptor { 45 protected struct HandlerDescriptor {
52 public ResultHandler<T> resultHandler; 46 public Action<T> resultHandler;
53 public ErrorHandler<T> errorHandler; 47 public Func<Exception,T> errorHandler;
54 public Action cancellHandler; 48 public Action cancellHandler;
55 public Promise<T> medium; 49 public Promise<T> medium;
56 50
57 public void Resolve(T result) { 51 public void Resolve(T result) {
58 if (resultHandler != null) { 52 if (resultHandler != null) {
102 const int TRANSITIONAL_STATE = 1; 96 const int TRANSITIONAL_STATE = 1;
103 const int SUCCEEDED_STATE = 2; 97 const int SUCCEEDED_STATE = 2;
104 const int REJECTED_STATE = 3; 98 const int REJECTED_STATE = 3;
105 const int CANCELLED_STATE = 4; 99 const int CANCELLED_STATE = 4;
106 100
107 readonly bool m_cancellable; 101 int m_childrenCount;
108
109 int m_childrenCount = 0;
110 int m_state; 102 int m_state;
111 T m_result; 103 T m_result;
112 Exception m_error; 104 Exception m_error;
113 105
114 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>(); 106 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
115 107
116 public Promise() { 108 public Promise() {
117 m_cancellable = true; 109 }
118 } 110
119 111 public Promise(IPromise parent) {
120 public Promise(IPromise parent, bool cancellable) {
121 m_cancellable = cancellable;
122 if (parent != null) 112 if (parent != null)
123 AddHandler( 113 AddHandler(
124 null, 114 null,
125 null, 115 null,
126 () => { 116 () => {
216 /// <summary> 206 /// <summary>
217 /// Отменяет операцию, если это возможно. 207 /// Отменяет операцию, если это возможно.
218 /// </summary> 208 /// </summary>
219 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks> 209 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
220 public void Cancel() { 210 public void Cancel() {
221 if (m_cancellable && BeginTransit()) { 211 if (BeginTransit()) {
222 CompleteTransit(CANCELLED_STATE); 212 CompleteTransit(CANCELLED_STATE);
223 OnStateChanged(); 213 OnStateChanged();
224 } 214 }
225 } 215 }
226 216
227 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel) { 217 public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) {
228 if (success == null && error == null && cancel == null) 218 if (success == null && error == null && cancel == null)
229 return this; 219 return this;
230 220
231 var medium = new Promise<T>(this, true); 221 var medium = new Promise<T>(this);
232 222
233 AddHandler(success, error, cancel, medium); 223 AddHandler(success, error, cancel, medium);
234 224
235 return medium; 225 return medium;
236 } 226 }
240 /// </summary> 230 /// </summary>
241 /// <param name="success">The handler of the successfully completed operation. 231 /// <param name="success">The handler of the successfully completed operation.
242 /// This handler will recieve an operation result as a parameter.</param> 232 /// This handler will recieve an operation result as a parameter.</param>
243 /// <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> 233 /// <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>
244 /// <returns>The new promise chained to this one.</returns> 234 /// <returns>The new promise chained to this one.</returns>
245 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) { 235 public IPromise<T> Then(Action<T> success, Func<Exception,T> error) {
246 if (success == null && error == null) 236 if (success == null && error == null)
247 return this; 237 return this;
248 238
249 var medium = new Promise<T>(this, true); 239 var medium = new Promise<T>(this);
250 240
251 AddHandler(success, error, null, medium); 241 AddHandler(success, error, null, medium);
252 242
253 return medium; 243 return medium;
254 } 244 }
255 245
256 246
257 247
258 248
259 public IPromise<T> Then(ResultHandler<T> success) { 249 public IPromise<T> Then(Action<T> success) {
260 if (success == null) 250 if (success == null)
261 return this; 251 return this;
262 252
263 var medium = new Promise<T>(this, true); 253 var medium = new Promise<T>(this);
264 254
265 AddHandler(success, null, null, medium); 255 AddHandler(success, null, null, medium);
266 256
267 return medium; 257 return medium;
268 } 258 }
282 /// Если данный метод вызвать несколько раз, либо добавить другие обработчики, то цепочка 272 /// Если данный метод вызвать несколько раз, либо добавить другие обработчики, то цепочка
283 /// не будет одиночной <see cref="IsExclusive"/> и, как следствие, будет невозможна отмена 273 /// не будет одиночной <see cref="IsExclusive"/> и, как следствие, будет невозможна отмена
284 /// всей цепи обещаний снизу (с самого последнего обещания). 274 /// всей цепи обещаний снизу (с самого последнего обещания).
285 /// </para> 275 /// </para>
286 /// </remarks> 276 /// </remarks>
287 public void Last(ResultHandler<T> success, ErrorHandler error, Action cancel) { 277 public void Last(Action<T> success, Action<Exception> error, Action cancel) {
288 if (success == null && error == null && cancel == null) 278 if (success == null && error == null && cancel == null)
289 return; 279 return;
290 280
291 ErrorHandler<T> errorHandler = null; 281 Func<Exception,T> errorHandler = null;
292 if (error != null) 282 if (error != null)
293 errorHandler = err => { 283 errorHandler = err => {
294 error(err); 284 error(err);
295 return default(T); 285 return default(T);
296 }; 286 };
297 AddHandler(success, errorHandler, cancel, null); 287 AddHandler(success, errorHandler, cancel, null);
298 } 288 }
299 289
300 public void Last(ResultHandler<T> success, ErrorHandler error) { 290 public void Last(Action<T> success, Action<Exception> error) {
301 Last(success, error, null); 291 Last(success, error, null);
302 } 292 }
303 293
304 public void Last(ResultHandler<T> success) { 294 public void Last(Action<T> success) {
305 Last(success, null, null); 295 Last(success, null, null);
306 } 296 }
307 297
308 public IPromise Error(ErrorHandler error) { 298 public IPromise Error(Action<Exception> error) {
309 if (error == null) 299 if (error == null)
310 return this; 300 return this;
311 301
312 var medium = new Promise<T>(this, true); 302 var medium = new Promise<T>(this);
313 303
314 AddHandler( 304 AddHandler(
315 null, 305 null,
316 e => { 306 e => {
317 error(e); 307 error(e);
330 /// <remarks> 320 /// <remarks>
331 /// If the specified handler throws an exception, this exception will be used to reject the promise. 321 /// If the specified handler throws an exception, this exception will be used to reject the promise.
332 /// </remarks> 322 /// </remarks>
333 /// <param name="handler">The error handler which returns the result of the promise.</param> 323 /// <param name="handler">The error handler which returns the result of the promise.</param>
334 /// <returns>New promise.</returns> 324 /// <returns>New promise.</returns>
335 public IPromise<T> Error(ErrorHandler<T> handler) { 325 public IPromise<T> Error(Func<Exception,T> handler) {
336 if (handler == null) 326 if (handler == null)
337 return this; 327 return this;
338 328
339 var medium = new Promise<T>(this, true); 329 var medium = new Promise<T>(this);
340 330
341 AddHandler(null, handler, null, medium); 331 AddHandler(null, handler, null, medium);
342 332
343 return medium; 333 return medium;
344 } 334 }
350 /// <param name="mapper">Преобразование результата к новому типу.</param> 340 /// <param name="mapper">Преобразование результата к новому типу.</param>
351 /// <param name="error">Обработчик ошибки. Данный обработчик получит 341 /// <param name="error">Обработчик ошибки. Данный обработчик получит
352 /// исключение возникшее при выполнении операции.</param> 342 /// исключение возникшее при выполнении операции.</param>
353 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns> 343 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns>
354 /// <param name = "cancel"></param> 344 /// <param name = "cancel"></param>
355 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error, Action cancel) { 345 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error, Action cancel) {
356 Safe.ArgumentNotNull(mapper, "mapper"); 346 Safe.ArgumentNotNull(mapper, "mapper");
357 347
358 // создаем прицепленное обещание 348 // создаем прицепленное обещание
359 var medium = new Promise<TNew>(this, true); 349 var medium = new Promise<TNew>(this);
360 350
361 ResultHandler<T> resultHandler = result => medium.Resolve(mapper(result)); 351 Action<T> resultHandler = result => medium.Resolve(mapper(result));
362 ErrorHandler<T> errorHandler; 352 Func<Exception,T> errorHandler;
363 if (error != null) 353 if (error != null)
364 errorHandler = e => { 354 errorHandler = e => {
365 try { 355 try {
366 medium.Resolve(error(e)); 356 medium.Resolve(error(e));
367 } catch (Exception e2) { 357 } catch (Exception e2) {
394 ); 384 );
395 385
396 return medium; 386 return medium;
397 } 387 }
398 388
399 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error) { 389 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error) {
400 return Then(mapper, error, null); 390 return Then(mapper, error, null);
401 } 391 }
402 392
403 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper) { 393 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper) {
404 return Then(mapper, null, null); 394 return Then(mapper, null, null);
405 } 395 }
406 396
407 /// <summary> 397 /// <summary>
408 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после 398 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после
413 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param> 403 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param>
414 /// <param name="error">Обработчик ошибки. Данный обработчик получит 404 /// <param name="error">Обработчик ошибки. Данный обработчик получит
415 /// исключение возникшее при выполнении текуещй операции.</param> 405 /// исключение возникшее при выполнении текуещй операции.</param>
416 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns> 406 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns>
417 /// <param name = "cancel"></param> 407 /// <param name = "cancel"></param>
418 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error, Action cancel) { 408 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error, Action cancel) {
419 409
420 Safe.ArgumentNotNull(chained, "chained"); 410 Safe.ArgumentNotNull(chained, "chained");
421 411
422 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно 412 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно
423 // создать посредника, к которому будут подвызяваться следующие обработчики. 413 // создать посредника, к которому будут подвызяваться следующие обработчики.
424 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы 414 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы
425 // передать через него результаты работы. 415 // передать через него результаты работы.
426 var medium = new Promise<TNew>(this, true); 416 var medium = new Promise<TNew>(this);
427 417
428 ResultHandler<T> resultHandler = delegate(T result) { 418 Action<T> resultHandler = delegate(T result) {
429 if (medium.IsCancelled) 419 if (medium.IsCancelled)
430 return; 420 return;
431 421
432 var promise = chained(result); 422 var promise = chained(result);
433 423
438 ); 428 );
439 429
440 // notify chained operation that it's not needed anymore 430 // notify chained operation that it's not needed anymore
441 // порядок вызова Then, Cancelled важен, поскольку от этого 431 // порядок вызова Then, Cancelled важен, поскольку от этого
442 // зависит IsExclusive 432 // зависит IsExclusive
443 medium.Cancelled(() => { 433 medium.Last(
444 if (promise.IsExclusive) 434 null,
445 promise.Cancel(); 435 null,
446 }); 436 () => {
437 if (promise.IsExclusive)
438 promise.Cancel();
439 }
440 );
447 }; 441 };
448 442
449 ErrorHandler<T> errorHandler; 443 Func<Exception,T> errorHandler;
450 444
451 if (error != null) 445 if (error != null)
452 errorHandler = delegate(Exception e) { 446 errorHandler = delegate(Exception e) {
453 try { 447 try {
454 var promise = error(e); 448 var promise = error(e);
496 ); 490 );
497 491
498 return medium; 492 return medium;
499 } 493 }
500 494
501 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error) { 495 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error) {
502 return Chain(chained, error, null); 496 return Chain(chained, error, null);
503 } 497 }
504 498
505 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained) { 499 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained) {
506 return Chain(chained, null, null); 500 return Chain(chained, null, null);
507 } 501 }
508 502
509 public IPromise<T> Cancelled(Action handler) { 503 public IPromise<T> Cancelled(Action handler) {
510 var medium = new Promise<T>(this,true); 504 var medium = new Promise<T>(this);
511 AddHandler(null, null, handler, medium); 505 AddHandler(null, null, handler, medium);
512 return medium; 506 return medium;
513 } 507 }
514 508
515 /// <summary> 509 /// <summary>
583 577
584 public T Join() { 578 public T Join() {
585 return Join(Timeout.Infinite); 579 return Join(Timeout.Infinite);
586 } 580 }
587 581
588 void AddHandler(ResultHandler<T> success, ErrorHandler<T> error, Action cancel, Promise<T> medium) { 582 void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium) {
589 if (success != null || error != null) 583 if (success != null || error != null)
590 Interlocked.Increment(ref m_childrenCount); 584 Interlocked.Increment(ref m_childrenCount);
591 585
592 var handler = new HandlerDescriptor { 586 var handler = new HandlerDescriptor {
593 resultHandler = success, 587 resultHandler = success,
757 return p; 751 return p;
758 } 752 }
759 753
760 #region IPromiseBase explicit implementation 754 #region IPromiseBase explicit implementation
761 755
762 IPromise IPromise.Then(Action success, ErrorHandler error, Action cancel) { 756 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
763 return Then( 757 return Then(
764 success != null ? new ResultHandler<T>(x => success()) : null, 758 success != null ? new Action<T>(x => success()) : null,
765 error != null ? new ErrorHandler<T>(e => { 759 error != null ? new Func<Exception,T>(e => {
766 error(e); 760 error(e);
767 return default(T); 761 return default(T);
768 }) : null, 762 }) : null,
769 cancel 763 cancel
770 ); 764 );
771 } 765 }
772 766
773 IPromise IPromise.Then(Action success, ErrorHandler error) { 767 IPromise IPromise.Then(Action success, Action<Exception> error) {
774 return Then( 768 return Then(
775 success != null ? new ResultHandler<T>(x => success()) : null, 769 success != null ? new Action<T>(x => success()) : null,
776 error != null ? new ErrorHandler<T>(e => { 770 error != null ? new Func<Exception,T>(e => {
777 error(e); 771 error(e);
778 return default(T); 772 return default(T);
779 }) : null 773 }) : null
780 ); 774 );
781 } 775 }
783 IPromise IPromise.Then(Action success) { 777 IPromise IPromise.Then(Action success) {
784 Safe.ArgumentNotNull(success, "success"); 778 Safe.ArgumentNotNull(success, "success");
785 return Then(x => success()); 779 return Then(x => success());
786 } 780 }
787 781
788 IPromise IPromise.Chain(Func<IPromise> chained, ErrorHandler<IPromise> error, Action cancel) { 782 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
789 return ChainNoResult(chained, error, cancel); 783 return ChainNoResult(chained, error, cancel);
790 } 784 }
791 785
792 IPromise ChainNoResult(Func<IPromise> chained, ErrorHandler<IPromise> error, Action cancel) { 786 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
793 Safe.ArgumentNotNull(chained, "chained"); 787 Safe.ArgumentNotNull(chained, "chained");
794 788
795 var medium = new Promise<object>(this, true); 789 var medium = new Promise<object>(this);
796 790
797 ResultHandler<T> resultHandler = delegate(T result) { 791 Action<T> resultHandler = delegate {
798 if (medium.IsCancelled) 792 if (medium.IsCancelled)
799 return; 793 return;
800 794
801 var promise = chained(); 795 var promise = chained();
802 796
813 if (promise.IsExclusive) 807 if (promise.IsExclusive)
814 promise.Cancel(); 808 promise.Cancel();
815 }); 809 });
816 }; 810 };
817 811
818 ErrorHandler<T> errorHandler; 812 Func<Exception,T> errorHandler;
819 813
820 if (error != null) 814 if (error != null)
821 errorHandler = delegate(Exception e) { 815 errorHandler = delegate(Exception e) {
822 try { 816 try {
823 var promise = error(e); 817 var promise = error(e);
864 null 858 null
865 ); 859 );
866 860
867 return medium; 861 return medium;
868 } 862 }
869 IPromise IPromise.Chain(Func<IPromise> chained, ErrorHandler<IPromise> error) { 863 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error) {
870 return ChainNoResult(chained, error, null); 864 return ChainNoResult(chained, error, null);
871 } 865 }
872 IPromise IPromise.Chain(Func<IPromise> chained) { 866 IPromise IPromise.Chain(Func<IPromise> chained) {
873 return ChainNoResult(chained, null, null); 867 return ChainNoResult(chained, null, null);
874 } 868 }
875 869
876 870
877 void IPromise.Last(Action success, ErrorHandler error, Action cancel) { 871 void IPromise.Last(Action success, Action<Exception> error, Action cancel) {
878 Last(x => success(), error, cancel); 872 Last(x => success(), error, cancel);
879 } 873 }
880 874
881 void IPromise.Last(Action success, ErrorHandler error) { 875 void IPromise.Last(Action success, Action<Exception> error) {
882 Last(x => success(), error, null); 876 Last(x => success(), error, null);
883 } 877 }
884 878
885 void IPromise.Last(Action success) { 879 void IPromise.Last(Action success) {
886 Last(x => success(), null, null); 880 Last(x => success(), null, null);
887 } 881 }
888 882
889 IPromise IPromise.Error(ErrorHandler error) { 883 IPromise IPromise.Error(Action<Exception> error) {
890 return Error(error); 884 return Error(error);
891 } 885 }
892 886
893 IPromise IPromise.Anyway(Action handler) { 887 IPromise IPromise.Anyway(Action handler) {
894 return Anyway(handler); 888 return Anyway(handler);