Mercurial > pub > ImplabNet
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); |