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