Mercurial > pub > ImplabNet
annotate Implab/PromiseT.cs @ 138:f75cfa58e3d4 v2
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
author | cin |
---|---|
date | Tue, 17 Feb 2015 18:16:26 +0300 |
parents | 656815cb7147 |
children | 8c0b95069066 |
rev | line source |
---|---|
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 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
42 class StubDeferred : IDeferred, IDeferred<T> { |
119 | 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 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
53 public void Resolve() { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
54 } |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
55 |
119 | 56 public void Reject(Exception error) { |
57 } | |
58 | |
59 #endregion | |
60 | |
61 #region ICancellable implementation | |
62 | |
63 public void Cancel() { | |
64 } | |
65 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
66 public void Cancel(Exception reason) { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
67 } |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
68 |
119 | 69 #endregion |
70 | |
71 | |
72 } | |
73 | |
74 class RemapDescriptor<T2> : IDeferred<T> { | |
75 readonly Func<T,T2> m_remap; | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
76 readonly Func<Exception, T2> m_failed; |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
77 readonly Func<Exception, T2> m_cancel; |
119 | 78 readonly IDeferred<T2> m_deferred; |
79 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
80 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<Exception, T2> cancel, IDeferred<T2> deferred ) { |
119 | 81 Debug.Assert(deferred != null); |
82 m_remap = remap; | |
83 m_failed = failed; | |
84 m_cancel = cancel; | |
85 m_deferred = deferred; | |
86 } | |
87 | |
88 | |
89 | |
90 #region IDeferred implementation | |
91 | |
92 public void Resolve(T value) { | |
93 if (m_remap != null) { | |
94 try { | |
95 m_deferred.Resolve(m_remap(value)); | |
96 } catch (Exception ex) { | |
97 Reject(ex); | |
98 } | |
99 } | |
100 } | |
101 | |
102 public void Reject(Exception error) { | |
103 if (m_failed != null) { | |
104 try { | |
105 m_deferred.Resolve(m_failed(error)); | |
106 } catch (Exception ex) { | |
107 m_deferred.Reject(ex); | |
108 } | |
109 } else { | |
110 m_deferred.Reject(error); | |
111 } | |
112 } | |
113 | |
114 | |
115 #endregion | |
116 | |
117 #region ICancellable implementation | |
118 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
119 public void Cancel(Exception reason) { |
119 | 120 if (m_cancel != null) { |
121 try { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
122 m_deferred.Resolve(m_cancel(reason)); |
119 | 123 } catch (Exception ex) { |
124 Reject(ex); | |
125 } | |
126 } else { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
127 m_deferred.Cancel(reason); |
119 | 128 } |
129 } | |
130 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
131 public void Cancel() { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
132 Cancel(null); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
133 } |
119 | 134 #endregion |
135 } | |
136 | |
137 class ListenerDescriptor : IDeferred<T> { | |
138 readonly Action m_handler; | |
139 readonly PromiseEventType m_events; | |
140 | |
141 public ListenerDescriptor(Action handler, PromiseEventType events) { | |
142 Debug.Assert(handler != null); | |
143 | |
144 m_handler = handler; | |
145 m_events = events; | |
146 } | |
147 | |
148 #region IDeferred implementation | |
149 | |
150 public void Resolve(T value) { | |
151 if (m_events.HasFlag(PromiseEventType.Success)) { | |
152 try { | |
153 m_handler(); | |
154 // Analysis disable once EmptyGeneralCatchClause | |
155 } catch { | |
156 } | |
157 } | |
158 } | |
159 | |
160 public void Reject(Exception error) { | |
161 if (m_events.HasFlag(PromiseEventType.Error)){ | |
162 try { | |
163 m_handler(); | |
164 // Analysis disable once EmptyGeneralCatchClause | |
165 } catch { | |
166 } | |
167 } | |
168 } | |
169 | |
170 #endregion | |
171 | |
172 #region ICancellable implementation | |
173 | |
174 public void Cancel() { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
175 Cancel(null); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
176 } |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
177 |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
178 public void Cancel(Exception reason) { |
119 | 179 if (m_events.HasFlag(PromiseEventType.Cancelled)){ |
180 try { | |
181 m_handler(); | |
182 // Analysis disable once EmptyGeneralCatchClause | |
183 } catch { | |
184 } | |
185 } | |
186 } | |
187 | |
188 #endregion | |
189 } | |
190 | |
191 class ValueEventDescriptor : IDeferred<T> { | |
192 readonly Action<T> m_success; | |
193 readonly Action<Exception> m_failed; | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
194 readonly Action<Exception> m_cancelled; |
119 | 195 readonly IDeferred<T> m_deferred; |
196 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
197 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action<Exception> cancelled, IDeferred<T> deferred) { |
119 | 198 Debug.Assert(deferred != null); |
199 | |
200 m_success = success; | |
201 m_failed = failed; | |
202 m_cancelled = cancelled; | |
203 m_deferred = deferred; | |
204 } | |
205 | |
206 #region IDeferred implementation | |
207 | |
208 public void Resolve(T value) { | |
209 if (m_success != null) { | |
210 try { | |
211 m_success(value); | |
212 m_deferred.Resolve(value); | |
213 } catch (Exception ex) { | |
214 Reject(ex); | |
215 } | |
216 } | |
217 } | |
218 | |
219 public void Reject(Exception error) { | |
220 if (m_failed != null) { | |
221 try { | |
222 m_failed(error); | |
223 m_deferred.Resolve(default(T)); | |
224 } catch(Exception ex) { | |
225 m_deferred.Reject(ex); | |
226 } | |
227 } else { | |
228 m_deferred.Reject(error); | |
229 } | |
230 } | |
231 | |
232 #endregion | |
233 | |
234 #region ICancellable implementation | |
235 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
236 public void Cancel(Exception reason) { |
119 | 237 if (m_cancelled != null) { |
238 try { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
239 m_cancelled(reason); |
119 | 240 m_deferred.Resolve(default(T)); |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
241 } catch (Exception ex) { |
119 | 242 Reject(ex); |
243 } | |
244 } else { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
245 m_deferred.Cancel(reason); |
119 | 246 } |
247 } | |
248 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
249 public void Cancel() { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
250 Cancel(null); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
251 } |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
252 |
119 | 253 #endregion |
254 } | |
255 | |
256 public class EventDescriptor : IDeferred<T> { | |
257 readonly Action m_success; | |
258 readonly Action<Exception> m_failed; | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
259 readonly Action<Exception> m_cancelled; |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
260 readonly IDeferred m_deferred; |
119 | 261 |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
262 public EventDescriptor(Action success, Action<Exception> failed, Action<Exception> cancelled, IDeferred deferred) { |
119 | 263 Debug.Assert(deferred != null); |
264 | |
265 m_success = success; | |
266 m_failed = failed; | |
267 m_cancelled = cancelled; | |
268 m_deferred = deferred; | |
269 } | |
270 | |
271 #region IDeferred implementation | |
272 | |
273 public void Resolve(T value) { | |
274 if (m_success != null) { | |
275 try { | |
276 m_success(); | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
277 m_deferred.Resolve(); |
119 | 278 } catch (Exception ex) { |
279 Reject(ex); | |
280 } | |
281 } | |
282 } | |
283 | |
284 public void Reject(Exception error) { | |
285 if (m_failed != null) { | |
286 try { | |
287 m_failed(error); | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
288 m_deferred.Resolve(); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
289 } catch (Exception ex) { |
119 | 290 m_deferred.Reject(ex); |
291 } | |
292 } else { | |
293 m_deferred.Reject(error); | |
294 } | |
295 } | |
296 | |
297 #endregion | |
298 | |
299 #region ICancellable implementation | |
300 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
301 public void Cancel(Exception reason) { |
119 | 302 if (m_cancelled != null) { |
303 try { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
304 m_cancelled(reason); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
305 m_deferred.Resolve(); |
119 | 306 } catch (Exception ex) { |
307 Reject(ex); | |
308 } | |
309 } else { | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
310 m_deferred.Cancel(reason); |
119 | 311 } |
312 } | |
313 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
314 public void Cancel() { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
315 Cancel(null); |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
316 } |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
317 |
119 | 318 #endregion |
319 } | |
320 | |
321 T m_result; | |
322 | |
323 public virtual void Resolve(T value) { | |
130
671f60cd0250
fixed Resove method bug when calling it on already cancelled promise
cin
parents:
119
diff
changeset
|
324 if (BeginSetResult()) { |
671f60cd0250
fixed Resove method bug when calling it on already cancelled promise
cin
parents:
119
diff
changeset
|
325 m_result = value; |
671f60cd0250
fixed Resove method bug when calling it on already cancelled promise
cin
parents:
119
diff
changeset
|
326 EndSetResult(); |
671f60cd0250
fixed Resove method bug when calling it on already cancelled promise
cin
parents:
119
diff
changeset
|
327 } |
119 | 328 } |
329 | |
330 public void Reject(Exception error) { | |
331 SetError(error); | |
332 } | |
333 | |
334 public Type PromiseType { | |
335 get { | |
336 return typeof(T); | |
337 } | |
338 } | |
339 | |
340 public new T Join() { | |
341 WaitResult(-1); | |
342 return m_result; | |
343 } | |
344 public new T Join(int timeout) { | |
345 WaitResult(timeout); | |
346 return m_result; | |
347 } | |
348 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
349 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) { |
119 | 350 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance)); |
351 return this; | |
352 } | |
353 | |
354 public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
355 AddHandler(new ValueEventDescriptor(success, error, null, StubDeferred.instance)); | |
356 return this; | |
357 } | |
358 | |
359 public IPromise<T> On(Action<T> success) { | |
360 AddHandler(new ValueEventDescriptor(success, null, null, StubDeferred.instance)); | |
361 return this; | |
362 } | |
363 | |
364 public IPromise<T> On(Action handler, PromiseEventType events) { | |
365 Listen(events, handler); | |
366 return this; | |
367 } | |
368 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
369 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel) { |
119 | 370 var promise = new Promise<T2>(); |
135 | 371 if (mapper != null) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
372 promise.On((Action)null, null, Cancel); |
119 | 373 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise)); |
374 return promise; | |
375 } | |
376 | |
377 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) { | |
378 var promise = new Promise<T2>(); | |
135 | 379 if (mapper != null) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
380 promise.On((Action)null, null, Cancel); |
119 | 381 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise)); |
382 return promise; | |
383 } | |
384 | |
385 public IPromise<T2> Then<T2>(Func<T, T2> mapper) { | |
386 var promise = new Promise<T2>(); | |
135 | 387 if (mapper != null) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
388 promise.On((Action)null, null, Cancel); |
119 | 389 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise)); |
390 return promise; | |
391 } | |
392 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
393 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) { |
119 | 394 // this promise will be resolved when an asyc operation is started |
395 var promise = new Promise<IPromise<T2>>(); | |
396 | |
397 AddHandler(new RemapDescriptor<IPromise<T2>>( | |
398 chained, | |
399 error, | |
400 cancel, | |
401 promise | |
402 )); | |
403 | |
404 var medium = new Promise<T2>(); | |
405 | |
406 if (chained != null) | |
407 medium.On(Cancel, PromiseEventType.Cancelled); | |
408 | |
409 // we need to connect started async operation with the medium | |
410 // if the async operation hasn't been started by the some reason | |
411 // report is to the medium | |
412 promise.On( | |
413 result => ConnectPromise<T2>(result, medium), | |
414 medium.Reject, | |
415 medium.Cancel | |
416 ); | |
417 | |
418 return medium; | |
419 } | |
420 | |
421 static void ConnectPromise<T2>(IPromise<T2> result, Promise<T2> medium) { | |
422 if (result != null) { | |
423 result.On( | |
424 medium.Resolve, | |
425 medium.Reject, | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
426 medium.Cancel |
119 | 427 ); |
428 medium.On(result.Cancel, PromiseEventType.Cancelled); | |
429 } else { | |
430 medium.Reject( | |
431 new NullReferenceException( | |
432 "The chained asynchronous operation returned" + | |
433 " 'null' where the promise instance is expected" | |
434 ) | |
435 ); | |
436 } | |
437 } | |
438 | |
439 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error) { | |
440 return Chain(chained, error, null); | |
441 } | |
442 | |
443 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained) { | |
444 return Chain(chained, null, null); | |
445 } | |
446 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
447 public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
448 var promise = new Promise(); |
119 | 449 if (success != null) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
450 promise.On(null, null, Cancel); |
119 | 451 |
452 AddHandler(new EventDescriptor(success, error, cancel, promise)); | |
453 | |
454 return promise; | |
455 } | |
456 | |
457 public IPromise Then(Action success, Action<Exception> error) { | |
458 return Then(success, error, null); | |
459 } | |
460 | |
461 public IPromise Then(Action success) { | |
462 return Then(success, null, null); | |
463 } | |
464 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
465 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) { |
119 | 466 var promise = new Promise<IPromise>(); |
467 | |
468 AddHandler( | |
469 new RemapDescriptor<IPromise>( | |
470 x => chained(), | |
471 error, | |
472 cancel, | |
473 promise | |
474 ) | |
475 ); | |
476 | |
477 var medium = new Promise(); | |
478 if (chained != null) | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
479 medium.On(null, null, Cancel); |
119 | 480 |
481 promise.On( | |
482 result => ConnectPromise(result, medium), | |
483 medium.Reject, | |
484 medium.Cancel | |
485 ); | |
486 | |
487 return medium; | |
488 } | |
489 | |
490 static void ConnectPromise(IPromise result, Promise medium) { | |
491 if (result != null) { | |
492 result.On( | |
493 medium.Resolve, | |
494 medium.Reject, | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
495 medium.Cancel |
119 | 496 ); |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
497 medium.On(null, null, result.Cancel); |
119 | 498 } else { |
499 medium.Reject( | |
500 new NullReferenceException( | |
501 "The chained asynchronous operation returned" + | |
502 " 'null' where the promise instance is expected" | |
503 ) | |
504 ); | |
505 } | |
506 } | |
507 | |
508 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
509 return Chain(chained, error, null); | |
510 } | |
511 | |
512 public IPromise Chain(Func<IPromise> chained) { | |
513 return Chain(chained, null, null); | |
514 } | |
515 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
516 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { |
119 | 517 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance)); |
518 return this; | |
519 } | |
520 | |
521 public IPromise On(Action success, Action<Exception> error) { | |
522 AddHandler(new EventDescriptor(success, error, null, StubDeferred.instance)); | |
523 return this; | |
524 } | |
525 | |
526 public IPromise On(Action success) { | |
527 Listen(PromiseEventType.Success, success); | |
528 return this; | |
529 } | |
530 | |
531 IPromise IPromise.On(Action handler, PromiseEventType events) { | |
532 Listen(events,handler); | |
533 return this; | |
534 } | |
535 | |
536 public IPromise<T2> Cast<T2>() { | |
537 return (IPromise<T2>)this; | |
538 } | |
539 | |
540 #region implemented abstract members of AbstractPromise | |
541 | |
542 protected override void SignalSuccess(IDeferred<T> handler) { | |
543 handler.Resolve(m_result); | |
544 } | |
545 | |
546 protected override void SignalError(IDeferred<T> handler, Exception error) { | |
547 handler.Reject(error); | |
548 } | |
549 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
550 protected override void SignalCancelled(IDeferred<T> handler, Exception reason) { |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
135
diff
changeset
|
551 handler.Cancel(reason); |
119 | 552 } |
553 | |
554 protected override void Listen(PromiseEventType events, Action handler) { | |
555 if (handler != null) | |
556 AddHandler(new ListenerDescriptor(handler, events)); | |
557 } | |
558 | |
559 #endregion | |
560 | |
561 public static IPromise<T> ResultToPromise(T value) { | |
562 var p = new Promise<T>(); | |
563 p.Resolve(value); | |
564 return p; | |
565 } | |
566 | |
567 public static IPromise<T> ExceptionToPromise(Exception error) { | |
568 var p = new Promise<T>(); | |
569 p.Reject(error); | |
570 return p; | |
571 } | |
572 | |
573 } | |
574 } |