##// END OF EJS Templates
Fixed chaining of promises with 'Then' method
cin -
r135:656815cb7147 v2
parent child
Show More
@@ -1,622 +1,628
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5
6 6 /// <summary>
7 7 /// Класс для асинхронного получения результатов. Так называемое "обещание".
8 8 /// </summary>
9 9 /// <typeparam name="T">Тип получаемого результата</typeparam>
10 10 /// <remarks>
11 11 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции,
12 12 /// клиент получив такое обещание может установить ряд обратных вызово для получения
13 13 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para>
14 14 /// <para>
15 15 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на
16 16 /// данные события клиент должен использовать методы <c>Then</c>.
17 17 /// </para>
18 18 /// <para>
19 19 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой),
20 20 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о
21 21 /// выполнении обещания.
22 22 /// </para>
23 23 /// <para>
24 24 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался,
25 25 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном
26 26 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в
27 27 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении
28 28 /// обещания.
29 29 /// </para>
30 30 /// <para>
31 31 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать
32 32 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует
33 33 /// использовать соответствующую форму методе <c>Then</c>.
34 34 /// </para>
35 35 /// <para>
36 36 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать
37 37 /// только инициатор обещания иначе могут возникнуть противоречия.
38 38 /// </para>
39 39 /// </remarks>
40 40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> {
41 41
42 42 class StubDeferred : IDeferred<T> {
43 43 public static readonly StubDeferred instance = new StubDeferred();
44 44
45 45 StubDeferred() {
46 46 }
47 47
48 48 #region IDeferred implementation
49 49
50 50 public void Resolve(T value) {
51 51 }
52 52
53 53 public void Reject(Exception error) {
54 54 }
55 55
56 56 #endregion
57 57
58 58 #region ICancellable implementation
59 59
60 60 public void Cancel() {
61 61 }
62 62
63 63 #endregion
64 64
65 65
66 66 }
67 67
68 68 class RemapDescriptor<T2> : IDeferred<T> {
69 69 readonly Func<T,T2> m_remap;
70 70 readonly Func<Exception,T2> m_failed;
71 71 readonly Func<T2> m_cancel;
72 72 readonly IDeferred<T2> m_deferred;
73 73
74 74 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<T2> cancel, IDeferred<T2> deferred ) {
75 75 Debug.Assert(deferred != null);
76 76 m_remap = remap;
77 77 m_failed = failed;
78 78 m_cancel = cancel;
79 79 m_deferred = deferred;
80 80 }
81 81
82 82
83 83
84 84 #region IDeferred implementation
85 85
86 86 public void Resolve(T value) {
87 87 if (m_remap != null) {
88 88 try {
89 89 m_deferred.Resolve(m_remap(value));
90 90 } catch (Exception ex) {
91 91 Reject(ex);
92 92 }
93 93 }
94 94 }
95 95
96 96 public void Reject(Exception error) {
97 97 if (m_failed != null) {
98 98 try {
99 99 m_deferred.Resolve(m_failed(error));
100 100 } catch (Exception ex) {
101 101 m_deferred.Reject(ex);
102 102 }
103 103 } else {
104 104 m_deferred.Reject(error);
105 105 }
106 106 }
107 107
108 108
109 109 #endregion
110 110
111 111 #region ICancellable implementation
112 112
113 113 public void Cancel() {
114 114 if (m_cancel != null) {
115 115 try {
116 116 m_deferred.Resolve(m_cancel());
117 117 } catch (Exception ex) {
118 118 Reject(ex);
119 119 }
120 120 } else {
121 121 m_deferred.Cancel();
122 122 }
123 123 }
124 124
125 125 #endregion
126 126 }
127 127
128 128 class ListenerDescriptor : IDeferred<T> {
129 129 readonly Action m_handler;
130 130 readonly PromiseEventType m_events;
131 131
132 132 public ListenerDescriptor(Action handler, PromiseEventType events) {
133 133 Debug.Assert(handler != null);
134 134
135 135 m_handler = handler;
136 136 m_events = events;
137 137 }
138 138
139 139 #region IDeferred implementation
140 140
141 141 public void Resolve(T value) {
142 142 if (m_events.HasFlag(PromiseEventType.Success)) {
143 143 try {
144 144 m_handler();
145 145 // Analysis disable once EmptyGeneralCatchClause
146 146 } catch {
147 147 }
148 148 }
149 149 }
150 150
151 151 public void Reject(Exception error) {
152 152 if (m_events.HasFlag(PromiseEventType.Error)){
153 153 try {
154 154 m_handler();
155 155 // Analysis disable once EmptyGeneralCatchClause
156 156 } catch {
157 157 }
158 158 }
159 159 }
160 160
161 161 #endregion
162 162
163 163 #region ICancellable implementation
164 164
165 165 public void Cancel() {
166 166 if (m_events.HasFlag(PromiseEventType.Cancelled)){
167 167 try {
168 168 m_handler();
169 169 // Analysis disable once EmptyGeneralCatchClause
170 170 } catch {
171 171 }
172 172 }
173 173 }
174 174
175 175 #endregion
176 176 }
177 177
178 178 class ValueEventDescriptor : IDeferred<T> {
179 179 readonly Action<T> m_success;
180 180 readonly Action<Exception> m_failed;
181 181 readonly Action m_cancelled;
182 182 readonly IDeferred<T> m_deferred;
183 183
184 184 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) {
185 185 Debug.Assert(deferred != null);
186 186
187 187 m_success = success;
188 188 m_failed = failed;
189 189 m_cancelled = cancelled;
190 190 m_deferred = deferred;
191 191 }
192 192
193 193 #region IDeferred implementation
194 194
195 195 public void Resolve(T value) {
196 196 if (m_success != null) {
197 197 try {
198 198 m_success(value);
199 199 m_deferred.Resolve(value);
200 200 } catch (Exception ex) {
201 201 Reject(ex);
202 202 }
203 203 }
204 204 }
205 205
206 206 public void Reject(Exception error) {
207 207 if (m_failed != null) {
208 208 try {
209 209 m_failed(error);
210 210 m_deferred.Resolve(default(T));
211 211 } catch(Exception ex) {
212 212 m_deferred.Reject(ex);
213 213 }
214 214 } else {
215 215 m_deferred.Reject(error);
216 216 }
217 217 }
218 218
219 219 #endregion
220 220
221 221 #region ICancellable implementation
222 222
223 223 public void Cancel() {
224 224 if (m_cancelled != null) {
225 225 try {
226 226 m_cancelled();
227 227 m_deferred.Resolve(default(T));
228 228 } catch(Exception ex) {
229 229 Reject(ex);
230 230 }
231 231 } else {
232 232 m_deferred.Cancel();
233 233 }
234 234 }
235 235
236 236 #endregion
237 237 }
238 238
239 239 public class EventDescriptor : IDeferred<T> {
240 240 readonly Action m_success;
241 241 readonly Action<Exception> m_failed;
242 242 readonly Action m_cancelled;
243 243 readonly IDeferred<T> m_deferred;
244 244
245 245 public EventDescriptor(Action success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) {
246 246 Debug.Assert(deferred != null);
247 247
248 248 m_success = success;
249 249 m_failed = failed;
250 250 m_cancelled = cancelled;
251 251 m_deferred = deferred;
252 252 }
253 253
254 254 #region IDeferred implementation
255 255
256 256 public void Resolve(T value) {
257 257 if (m_success != null) {
258 258 try {
259 259 m_success();
260 260 m_deferred.Resolve(value);
261 261 } catch (Exception ex) {
262 262 Reject(ex);
263 263 }
264 264 }
265 265 }
266 266
267 267 public void Reject(Exception error) {
268 268 if (m_failed != null) {
269 269 try {
270 270 m_failed(error);
271 271 m_deferred.Resolve(default(T));
272 272 }catch (Exception ex)
273 273 {
274 274 m_deferred.Reject(ex);
275 275 }
276 276 } else {
277 277 m_deferred.Reject(error);
278 278 }
279 279
280 280 }
281 281
282 282 #endregion
283 283
284 284 #region ICancellable implementation
285 285
286 286 public void Cancel() {
287 287 if (m_cancelled != null) {
288 288 try {
289 289 m_cancelled();
290 290 m_deferred.Resolve(default(T));
291 291 } catch (Exception ex) {
292 292 Reject(ex);
293 293 }
294 294 } else {
295 295 m_deferred.Cancel();
296 296 }
297 297 }
298 298
299 299 #endregion
300 300 }
301 301
302 302 T m_result;
303 303
304 304 public virtual void Resolve(T value) {
305 305 if (BeginSetResult()) {
306 306 m_result = value;
307 307 EndSetResult();
308 308 }
309 309 }
310 310
311 311 public void Reject(Exception error) {
312 312 SetError(error);
313 313 }
314 314
315 315 public Type PromiseType {
316 316 get {
317 317 return typeof(T);
318 318 }
319 319 }
320 320
321 321 public new T Join() {
322 322 WaitResult(-1);
323 323 return m_result;
324 324 }
325 325 public new T Join(int timeout) {
326 326 WaitResult(timeout);
327 327 return m_result;
328 328 }
329 329
330 330 public IPromise<T> On(Action<T> success, Action<Exception> error, Action cancel) {
331 331 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance));
332 332 return this;
333 333 }
334 334
335 335 public IPromise<T> On(Action<T> success, Action<Exception> error) {
336 336 AddHandler(new ValueEventDescriptor(success, error, null, StubDeferred.instance));
337 337 return this;
338 338 }
339 339
340 340 public IPromise<T> On(Action<T> success) {
341 341 AddHandler(new ValueEventDescriptor(success, null, null, StubDeferred.instance));
342 342 return this;
343 343 }
344 344
345 345 public IPromise<T> On(Action handler, PromiseEventType events) {
346 346 Listen(events, handler);
347 347 return this;
348 348 }
349 349
350 350 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<T2> cancel) {
351 351 var promise = new Promise<T2>();
352 if (mapper != null)
353 promise.On(Cancel, PromiseEventType.Cancelled);
352 354 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise));
353 355 return promise;
354 356 }
355 357
356 358 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) {
357 359 var promise = new Promise<T2>();
360 if (mapper != null)
361 promise.On(Cancel, PromiseEventType.Cancelled);
358 362 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise));
359 363 return promise;
360 364 }
361 365
362 366 public IPromise<T2> Then<T2>(Func<T, T2> mapper) {
363 367 var promise = new Promise<T2>();
368 if (mapper != null)
369 promise.On(Cancel, PromiseEventType.Cancelled);
364 370 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise));
365 371 return promise;
366 372 }
367 373
368 374 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<IPromise<T2>> cancel) {
369 375 // this promise will be resolved when an asyc operation is started
370 376 var promise = new Promise<IPromise<T2>>();
371 377
372 378 AddHandler(new RemapDescriptor<IPromise<T2>>(
373 379 chained,
374 380 error,
375 381 cancel,
376 382 promise
377 383 ));
378 384
379 385 var medium = new Promise<T2>();
380 386
381 387 if (chained != null)
382 388 medium.On(Cancel, PromiseEventType.Cancelled);
383 389
384 390 // we need to connect started async operation with the medium
385 391 // if the async operation hasn't been started by the some reason
386 392 // report is to the medium
387 393 promise.On(
388 394 result => ConnectPromise<T2>(result, medium),
389 395 medium.Reject,
390 396 medium.Cancel
391 397 );
392 398
393 399 return medium;
394 400 }
395 401
396 402 static void ConnectPromise<T2>(IPromise<T2> result, Promise<T2> medium) {
397 403 if (result != null) {
398 404 result.On(
399 405 medium.Resolve,
400 406 medium.Reject,
401 407 () => medium.Reject(new OperationCanceledException())
402 408 );
403 409 medium.On(result.Cancel, PromiseEventType.Cancelled);
404 410 } else {
405 411 medium.Reject(
406 412 new NullReferenceException(
407 413 "The chained asynchronous operation returned" +
408 414 " 'null' where the promise instance is expected"
409 415 )
410 416 );
411 417 }
412 418 }
413 419
414 420 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error) {
415 421 return Chain(chained, error, null);
416 422 }
417 423
418 424 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained) {
419 425 return Chain(chained, null, null);
420 426 }
421 427
422 428 public IPromise<T2> Error<T2>(Func<Exception, T2> error) {
423 429 var promise = new Promise<T2>();
424 430 if (error != null)
425 431 On(
426 432 (Action<T>)null,
427 433 ex => {
428 434 try {
429 435 promise.Resolve(error(ex));
430 436 } catch (Exception ex2) {
431 437 promise.Reject(ex2);
432 438 }
433 439 }
434 440 );
435 441 else
436 442 Listen(PromiseEventType.Error, () => promise.Resolve(default(T2)));
437 443 return promise;
438 444 }
439 445
440 446 public IPromise<T2> Cancelled<T2>(Func<T2> handler) {
441 447 var promise = new Promise<T2>();
442 448 if (handler != null)
443 449 On(
444 450 (Action<T>)null,
445 451 null,
446 452 () => {
447 453 try {
448 454 promise.Resolve(handler());
449 455 } catch (Exception ex) {
450 456 promise.Reject(ex);
451 457 }
452 458 });
453 459 else
454 460 Listen(PromiseEventType.Cancelled, () => promise.Resolve(default(T2)));
455 461 return promise;
456 462 }
457 463
458 464 public IPromise Then(Action success, Action<Exception> error, Action cancel) {
459 465 var promise = new Promise<T>();
460 466 if (success != null)
461 467 promise.On(Cancel, PromiseEventType.Cancelled);
462 468
463 469 AddHandler(new EventDescriptor(success, error, cancel, promise));
464 470
465 471 return promise;
466 472 }
467 473
468 474 public IPromise Then(Action success, Action<Exception> error) {
469 475 return Then(success, error, null);
470 476 }
471 477
472 478 public IPromise Then(Action success) {
473 479 return Then(success, null, null);
474 480 }
475 481
476 482 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel) {
477 483 var promise = new Promise<IPromise>();
478 484
479 485 AddHandler(
480 486 new RemapDescriptor<IPromise>(
481 487 x => chained(),
482 488 error,
483 489 cancel,
484 490 promise
485 491 )
486 492 );
487 493
488 494 var medium = new Promise();
489 495 if (chained != null)
490 496 medium.On(Cancel, PromiseEventType.Cancelled);
491 497
492 498 promise.On(
493 499 result => ConnectPromise(result, medium),
494 500 medium.Reject,
495 501 medium.Cancel
496 502 );
497 503
498 504 return medium;
499 505 }
500 506
501 507 static void ConnectPromise(IPromise result, Promise medium) {
502 508 if (result != null) {
503 509 result.On(
504 510 medium.Resolve,
505 511 medium.Reject,
506 512 () => medium.Reject(new OperationCanceledException())
507 513 );
508 514 medium.On(result.Cancel, PromiseEventType.Cancelled);
509 515 } else {
510 516 medium.Reject(
511 517 new NullReferenceException(
512 518 "The chained asynchronous operation returned" +
513 519 " 'null' where the promise instance is expected"
514 520 )
515 521 );
516 522 }
517 523 }
518 524
519 525 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) {
520 526 return Chain(chained, error, null);
521 527 }
522 528
523 529 public IPromise Chain(Func<IPromise> chained) {
524 530 return Chain(chained, null, null);
525 531 }
526 532
527 533 public IPromise On(Action success, Action<Exception> error, Action cancel) {
528 534 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance));
529 535 return this;
530 536 }
531 537
532 538 public IPromise On(Action success, Action<Exception> error) {
533 539 AddHandler(new EventDescriptor(success, error, null, StubDeferred.instance));
534 540 return this;
535 541 }
536 542
537 543 public IPromise On(Action success) {
538 544 Listen(PromiseEventType.Success, success);
539 545 return this;
540 546 }
541 547
542 548 IPromise IPromise.On(Action handler, PromiseEventType events) {
543 549 Listen(events,handler);
544 550 return this;
545 551 }
546 552
547 553 public IPromise Error(Action<Exception> error) {
548 554 var promise = new Promise();
549 555 if (error != null)
550 556 On(
551 557 (Action<T>)null,
552 558 ex => {
553 559 try {
554 560 error(ex);
555 561 promise.Resolve();
556 562 } catch (Exception ex2) {
557 563 promise.Reject(ex2);
558 564 }
559 565 });
560 566 else
561 567 Listen(PromiseEventType.Error, promise.Resolve);
562 568 return promise;
563 569 }
564 570
565 571 public IPromise Cancelled(Action handler) {
566 572 var promise = new Promise();
567 573 if (handler != null)
568 574 On(
569 575 (Action<T>)null,
570 576 null,
571 577 () => {
572 578 try {
573 579 handler();
574 580 promise.Resolve();
575 581 } catch (Exception ex) {
576 582 promise.Reject(ex);
577 583 }
578 584 });
579 585 else
580 586 Listen(PromiseEventType.Cancelled, promise.Resolve);
581 587 return promise;
582 588 }
583 589
584 590 public IPromise<T2> Cast<T2>() {
585 591 return (IPromise<T2>)this;
586 592 }
587 593
588 594 #region implemented abstract members of AbstractPromise
589 595
590 596 protected override void SignalSuccess(IDeferred<T> handler) {
591 597 handler.Resolve(m_result);
592 598 }
593 599
594 600 protected override void SignalError(IDeferred<T> handler, Exception error) {
595 601 handler.Reject(error);
596 602 }
597 603
598 604 protected override void SignalCancelled(IDeferred<T> handler) {
599 605 handler.Cancel();
600 606 }
601 607
602 608 protected override void Listen(PromiseEventType events, Action handler) {
603 609 if (handler != null)
604 610 AddHandler(new ListenerDescriptor(handler, events));
605 611 }
606 612
607 613 #endregion
608 614
609 615 public static IPromise<T> ResultToPromise(T value) {
610 616 var p = new Promise<T>();
611 617 p.Resolve(value);
612 618 return p;
613 619 }
614 620
615 621 public static IPromise<T> ExceptionToPromise(Exception error) {
616 622 var p = new Promise<T>();
617 623 p.Reject(error);
618 624 return p;
619 625 }
620 626
621 627 }
622 628 }
General Comments 0
You need to be logged in to leave comments. Login now