@@ -0,0 +1,135 | |||
|
1 | using System; | |
|
2 | using System.Collections.Generic; | |
|
3 | using System.Threading; | |
|
4 | using System.Collections; | |
|
5 | ||
|
6 | namespace Implab.Parallels { | |
|
7 | public class MTCustomQueue<TNode> : IEnumerable<TNode> where TNode : MTCustomQueueNode<TNode> { | |
|
8 | TNode m_first; | |
|
9 | TNode m_last; | |
|
10 | ||
|
11 | public void Enqueue(TNode next) { | |
|
12 | Thread.MemoryBarrier(); | |
|
13 | ||
|
14 | var last = m_last; | |
|
15 | ||
|
16 | // Interlocaked.CompareExchange implies Thread.MemoryBarrier(); | |
|
17 | // to ensure that the next node is completely constructed | |
|
18 | while (last != Interlocked.CompareExchange(ref m_last, next, last)) | |
|
19 | last = m_last; | |
|
20 | ||
|
21 | if (last != null) | |
|
22 | last.next = next; | |
|
23 | else | |
|
24 | m_first = next; | |
|
25 | } | |
|
26 | ||
|
27 | public bool TryDequeue(out TNode node) { | |
|
28 | TNode first; | |
|
29 | TNode next; | |
|
30 | node = null; | |
|
31 | ||
|
32 | Thread.MemoryBarrier(); | |
|
33 | do { | |
|
34 | first = m_first; | |
|
35 | if (first == null) | |
|
36 | return false; | |
|
37 | next = first.next; | |
|
38 | if (next == null) { | |
|
39 | // this is the last element, | |
|
40 | // then try to update the tail | |
|
41 | if (first != Interlocked.CompareExchange(ref m_last, null, first)) { | |
|
42 | // this is the race condition | |
|
43 | if (m_last == null) | |
|
44 | // the queue is empty | |
|
45 | return false; | |
|
46 | // tail has been changed, we need to restart | |
|
47 | continue; | |
|
48 | } | |
|
49 | ||
|
50 | // tail succesfully updated and first.next will never be changed | |
|
51 | // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null | |
|
52 | // however the parallel writer may update the m_first since the m_last is null | |
|
53 | ||
|
54 | // so we need to fix inconsistency by setting m_first to null or if it has been | |
|
55 | // updated by the writer already then we should just to give up | |
|
56 | Interlocked.CompareExchange(ref m_first, null, first); | |
|
57 | break; | |
|
58 | ||
|
59 | } | |
|
60 | if (first == Interlocked.CompareExchange(ref m_first, next, first)) | |
|
61 | // head succesfully updated | |
|
62 | break; | |
|
63 | } while (true); | |
|
64 | ||
|
65 | node = first; | |
|
66 | return true; | |
|
67 | } | |
|
68 | ||
|
69 | #region IEnumerable implementation | |
|
70 | ||
|
71 | class Enumerator : IEnumerator<TNode> { | |
|
72 | TNode m_current; | |
|
73 | TNode m_first; | |
|
74 | ||
|
75 | public Enumerator(TNode first) { | |
|
76 | m_first = first; | |
|
77 | } | |
|
78 | ||
|
79 | #region IEnumerator implementation | |
|
80 | ||
|
81 | public bool MoveNext() { | |
|
82 | m_current = m_current == null ? m_first : m_current.next; | |
|
83 | return m_current != null; | |
|
84 | } | |
|
85 | ||
|
86 | public void Reset() { | |
|
87 | m_current = null; | |
|
88 | } | |
|
89 | ||
|
90 | object IEnumerator.Current { | |
|
91 | get { | |
|
92 | if (m_current == null) | |
|
93 | throw new InvalidOperationException(); | |
|
94 | return m_current; | |
|
95 | } | |
|
96 | } | |
|
97 | ||
|
98 | #endregion | |
|
99 | ||
|
100 | #region IDisposable implementation | |
|
101 | ||
|
102 | public void Dispose() { | |
|
103 | } | |
|
104 | ||
|
105 | #endregion | |
|
106 | ||
|
107 | #region IEnumerator implementation | |
|
108 | ||
|
109 | public TNode Current { | |
|
110 | get { | |
|
111 | if (m_current == null) | |
|
112 | throw new InvalidOperationException(); | |
|
113 | return m_current; | |
|
114 | } | |
|
115 | } | |
|
116 | ||
|
117 | #endregion | |
|
118 | } | |
|
119 | ||
|
120 | public IEnumerator<TNode> GetEnumerator() { | |
|
121 | return new Enumerator(m_first); | |
|
122 | } | |
|
123 | ||
|
124 | #endregion | |
|
125 | ||
|
126 | #region IEnumerable implementation | |
|
127 | ||
|
128 | IEnumerator IEnumerable.GetEnumerator() { | |
|
129 | return GetEnumerator(); | |
|
130 | } | |
|
131 | ||
|
132 | #endregion | |
|
133 | } | |
|
134 | } | |
|
135 |
@@ -0,0 +1,6 | |||
|
1 | namespace Implab.Parallels { | |
|
2 | public class MTCustomQueueNode<TNode> where TNode : MTCustomQueueNode<TNode> { | |
|
3 | public TNode next; | |
|
4 | } | |
|
5 | } | |
|
6 |
@@ -42,7 +42,13 namespace Implab.Fx | |||
|
42 | 42 | { |
|
43 | 43 | var anim = ctl.AnimateTransparency(0); |
|
44 | 44 | |
|
45 | return anim.Play().DispatchToControl(ctl).Then(frm => frm.Close()); | |
|
45 | return anim | |
|
46 | .Play() | |
|
47 | .DispatchToControl(ctl) | |
|
48 | .Then(frm => { | |
|
49 | frm.Close(); | |
|
50 | return frm; | |
|
51 | }); | |
|
46 | 52 | } |
|
47 | 53 | |
|
48 | 54 | public static IPromise<T> OverlayFadeIn<T>(this Form that, T overlay) where T : Form |
@@ -19,9 +19,9 namespace Implab.Fx { | |||
|
19 | 19 | m_target = target; |
|
20 | 20 | } |
|
21 | 21 | |
|
22 |
protected override void InvokeHandler(Handler |
|
|
22 | protected override void InvokeHandler(AbstractHandler handler) { | |
|
23 | 23 | if (m_target.InvokeRequired) |
|
24 |
m_target.BeginInvoke(new Action<Handler |
|
|
24 | m_target.BeginInvoke(new Action<AbstractHandler>(base.InvokeHandler), handler); | |
|
25 | 25 | else |
|
26 | 26 | base.InvokeHandler(handler); |
|
27 | 27 | } |
@@ -426,8 +426,11 namespace Implab.Test { | |||
|
426 | 426 | hemStarted.Set(); |
|
427 | 427 | // запускаем две асинхронные операции |
|
428 | 428 | var result = PromiseHelper |
|
429 | .Sleep(10000, "HEM ENABLED!!!") | |
|
430 |
.Then(s => |
|
|
429 | .Sleep(100000000, "HEM ENABLED!!!") | |
|
430 | .Then(s => { | |
|
431 | pSurvive.Resolve(false); | |
|
432 | return s; | |
|
433 | }); | |
|
431 | 434 | |
|
432 | 435 | result |
|
433 | 436 | .Cancelled(() => pSurvive.Resolve(true)); |
@@ -13,12 +13,6 namespace Implab { | |||
|
13 | 13 | |
|
14 | 14 | void On(Action<T> success); |
|
15 | 15 | |
|
16 | IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel); | |
|
17 | ||
|
18 | IPromise<T> Then(Action<T> success, Func<Exception,T> error); | |
|
19 | ||
|
20 | IPromise<T> Then(Action<T> success); | |
|
21 | ||
|
22 | 16 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error, Action cancel); |
|
23 | 17 | |
|
24 | 18 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error); |
@@ -148,6 +148,8 | |||
|
148 | 148 | <Compile Include="IComponentContainer.cs" /> |
|
149 | 149 | <Compile Include="MTComponentContainer.cs" /> |
|
150 | 150 | <Compile Include="PromiseEventType.cs" /> |
|
151 | <Compile Include="Parallels\MTCustomQueue.cs" /> | |
|
152 | <Compile Include="Parallels\MTCustomQueueNode.cs" /> | |
|
151 | 153 | </ItemGroup> |
|
152 | 154 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
153 | 155 | <ItemGroup /> |
@@ -42,53 +42,68 namespace Implab { | |||
|
42 | 42 | /// </remarks> |
|
43 | 43 | public class Promise<T> : IPromise<T> { |
|
44 | 44 | |
|
45 | protected struct HandlerDescriptor { | |
|
46 |
public |
|
|
47 |
public |
|
|
48 |
public |
|
|
49 | public Promise<T> medium; | |
|
45 | protected abstract class AbstractHandler : MTCustomQueueNode<AbstractHandler> { | |
|
46 | public abstract void Resolve(T result); | |
|
47 | public abstract void Reject(Exception error); | |
|
48 | public abstract void Cancel(); | |
|
49 | } | |
|
50 | ||
|
51 | protected class HandlerDescriptor<T2> : AbstractHandler { | |
|
52 | ||
|
53 | readonly Func<T,T2> m_resultHandler; | |
|
54 | readonly Func<Exception,T2> m_errorHandler; | |
|
55 | readonly Action m_cancellHandler; | |
|
56 | readonly Promise<T2> m_medium; | |
|
50 | 57 | |
|
51 | public void Resolve(T result) { | |
|
52 |
|
|
|
58 | public HandlerDescriptor(Func<T,T2> resultHandler, Func<Exception,T2> errorHandler, Action cancelHandler, Promise<T2> medium) { | |
|
59 | m_resultHandler = resultHandler; | |
|
60 | m_errorHandler = errorHandler; | |
|
61 | m_cancellHandler = cancelHandler; | |
|
62 | m_medium = medium; | |
|
63 | } | |
|
64 | ||
|
65 | public override void Resolve(T result) { | |
|
66 | if (m_resultHandler != null) { | |
|
53 | 67 | try { |
|
54 |
|
|
|
68 | if (m_medium != null) | |
|
69 | m_medium.Resolve(m_resultHandler(result)); | |
|
70 | else | |
|
71 | m_resultHandler(result); | |
|
55 | 72 | } catch (Exception e) { |
|
56 | 73 | Reject(e); |
|
57 | return; | |
|
58 | 74 | } |
|
59 | } | |
|
60 |
|
|
|
61 | medium.Resolve(result); | |
|
75 | } else if(m_medium != null) | |
|
76 | m_medium.Resolve(default(T2)); | |
|
62 | 77 | } |
|
63 | 78 | |
|
64 | public void Reject(Exception err) { | |
|
65 | if (errorHandler != null) { | |
|
79 | public override void Reject(Exception error) { | |
|
80 | if (m_errorHandler != null) { | |
|
66 | 81 | try { |
|
67 | var res = errorHandler(err); | |
|
68 | if (medium != null) | |
|
69 | medium.Resolve(res); | |
|
82 | var res = m_errorHandler(error); | |
|
83 | if (m_medium != null) | |
|
84 | m_medium.Resolve(res); | |
|
70 | 85 | /*} catch (TransientPromiseException err2) { |
|
71 | 86 | if (medium != null) |
|
72 | 87 | medium.Reject(err2.InnerException);*/ |
|
73 | 88 | } catch (Exception err2) { |
|
74 | if (medium != null) | |
|
75 | medium.Reject(err2); | |
|
89 | if (m_medium != null) | |
|
90 | m_medium.Reject(err2); | |
|
76 | 91 | } |
|
77 | } else if (medium != null) | |
|
78 | medium.Reject(err); | |
|
92 | } else if (m_medium != null) | |
|
93 | m_medium.Reject(error); | |
|
79 | 94 | } |
|
80 | 95 | |
|
81 | public void Cancel() { | |
|
82 | if (cancellHandler != null) { | |
|
96 | public override void Cancel() { | |
|
97 | if (m_cancellHandler != null) { | |
|
83 | 98 | try { |
|
84 | cancellHandler(); | |
|
99 | m_cancellHandler(); | |
|
85 | 100 | } catch (Exception err) { |
|
86 | 101 | Reject(err); |
|
87 | 102 | return; |
|
88 | 103 | } |
|
89 | 104 | } |
|
90 | if (medium != null) | |
|
91 | medium.Cancel(); | |
|
105 | if (m_medium != null) | |
|
106 | m_medium.Cancel(); | |
|
92 | 107 | } |
|
93 | 108 | } |
|
94 | 109 | |
@@ -103,14 +118,15 namespace Implab { | |||
|
103 | 118 | T m_result; |
|
104 | 119 | Exception m_error; |
|
105 | 120 | |
|
106 |
readonly MTQueue<Handler |
|
|
121 | readonly MTCustomQueue<AbstractHandler> m_handlers = new MTCustomQueue<AbstractHandler>(); | |
|
122 | //readonly MTQueue<AbstractHandler> m_handlers = new MTQueue<AbstractHandler>(); | |
|
107 | 123 | |
|
108 | 124 | public Promise() { |
|
109 | 125 | } |
|
110 | 126 | |
|
111 | 127 | public Promise(IPromise parent) { |
|
112 | 128 | if (parent != null) |
|
113 | AddHandler( | |
|
129 | AddHandler<T>( | |
|
114 | 130 | null, |
|
115 | 131 | null, |
|
116 | 132 | () => { |
@@ -215,49 +231,6 namespace Implab { | |||
|
215 | 231 | } |
|
216 | 232 | } |
|
217 | 233 | |
|
218 | public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) { | |
|
219 | if (success == null && error == null && cancel == null) | |
|
220 | return this; | |
|
221 | ||
|
222 | var medium = new Promise<T>(this); | |
|
223 | ||
|
224 | AddHandler(success, error, cancel, medium, true); | |
|
225 | ||
|
226 | return medium; | |
|
227 | } | |
|
228 | ||
|
229 | /// <summary> | |
|
230 | /// Adds new handlers to this promise. | |
|
231 | /// </summary> | |
|
232 | /// <param name="success">The handler of the successfully completed operation. | |
|
233 | /// This handler will recieve an operation result as a parameter.</param> | |
|
234 | /// <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> | |
|
235 | /// <returns>The new promise chained to this one.</returns> | |
|
236 | public IPromise<T> Then(Action<T> success, Func<Exception,T> error) { | |
|
237 | if (success == null && error == null) | |
|
238 | return this; | |
|
239 | ||
|
240 | var medium = new Promise<T>(this); | |
|
241 | ||
|
242 | AddHandler(success, error, null, medium, true); | |
|
243 | ||
|
244 | return medium; | |
|
245 | } | |
|
246 | ||
|
247 | ||
|
248 | ||
|
249 | ||
|
250 | public IPromise<T> Then(Action<T> success) { | |
|
251 | if (success == null) | |
|
252 | return this; | |
|
253 | ||
|
254 | var medium = new Promise<T>(this); | |
|
255 | ||
|
256 | AddHandler(success, null, null, medium, true); | |
|
257 | ||
|
258 | return medium; | |
|
259 | } | |
|
260 | ||
|
261 | 234 | /// <summary> |
|
262 | 235 | /// Последний обработчик в цепочки обещаний. |
|
263 | 236 | /// </summary> |
@@ -279,13 +252,19 namespace Implab { | |||
|
279 | 252 | if (success == null && error == null && cancel == null) |
|
280 | 253 | return; |
|
281 | 254 | |
|
282 | Func<Exception,T> errorHandler = null; | |
|
283 | if (error != null) | |
|
284 | errorHandler = err => { | |
|
285 |
|
|
|
255 | AddHandler( | |
|
256 | success != null ? new Func<T,T>(x => { | |
|
257 | success(x); | |
|
258 | return x; | |
|
259 | }) : null, | |
|
260 | error != null ? new Func<Exception,T>(e => { | |
|
261 | error(e); | |
|
286 | 262 | return default(T); |
|
287 |
} |
|
|
288 | AddHandler(success, errorHandler, cancel, null, false); | |
|
263 | }) : null, | |
|
264 | cancel, | |
|
265 | null, | |
|
266 | false | |
|
267 | ); | |
|
289 | 268 | } |
|
290 | 269 | |
|
291 | 270 | public void On(Action<T> success, Action<Exception> error) { |
@@ -299,7 +278,10 namespace Implab { | |||
|
299 | 278 | public void On(Action handler, PromiseEventType events) { |
|
300 | 279 | Safe.ArgumentNotNull(handler, "handler"); |
|
301 | 280 | |
|
302 |
|
|
|
281 | Func<T,T> success = events.HasFlag(PromiseEventType.Success) ? new Func<T,T>(x => { | |
|
282 | handler(); | |
|
283 | return x; | |
|
284 | }) : null; | |
|
303 | 285 | Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => { |
|
304 | 286 | handler(); |
|
305 | 287 | return default(T); |
@@ -363,39 +345,11 namespace Implab { | |||
|
363 | 345 | // создаем прицепленное обещание |
|
364 | 346 | var medium = new Promise<TNew>(this); |
|
365 | 347 | |
|
366 | Action<T> resultHandler = result => medium.Resolve(mapper(result)); | |
|
367 | Func<Exception,T> errorHandler; | |
|
368 | if (error != null) | |
|
369 | errorHandler = e => { | |
|
370 | try { | |
|
371 | medium.Resolve(error(e)); | |
|
372 | } catch (Exception e2) { | |
|
373 | // в случае ошибки нужно передать исключение дальше по цепочке | |
|
374 | medium.Reject(e2); | |
|
375 | } | |
|
376 | return default(T); | |
|
377 | }; | |
|
378 | else | |
|
379 | errorHandler = e => { | |
|
380 | medium.Reject(e); | |
|
381 | return default(T); | |
|
382 | }; | |
|
383 | ||
|
384 | Action cancelHandler; | |
|
385 | if (cancel != null) | |
|
386 | cancelHandler = () => { | |
|
387 | cancel(); | |
|
388 | medium.Cancel(); | |
|
389 | }; | |
|
390 | else | |
|
391 | cancelHandler = medium.Cancel; | |
|
392 | ||
|
393 | ||
|
394 | 348 | AddHandler( |
|
395 |
|
|
|
396 |
error |
|
|
397 |
cancel |
|
|
398 |
|
|
|
349 | mapper, | |
|
350 | error, | |
|
351 | cancel, | |
|
352 | medium, | |
|
399 | 353 | true |
|
400 | 354 | ); |
|
401 | 355 | |
@@ -431,9 +385,9 namespace Implab { | |||
|
431 | 385 | // передать через него результаты работы. |
|
432 | 386 | var medium = new Promise<TNew>(this); |
|
433 | 387 | |
|
434 |
|
|
|
388 | Func<T,T> resultHandler = delegate(T result) { | |
|
435 | 389 | if (medium.IsCancelled) |
|
436 | return; | |
|
390 | return default(T); | |
|
437 | 391 | |
|
438 | 392 | var promise = chained(result); |
|
439 | 393 | |
@@ -454,6 +408,8 namespace Implab { | |||
|
454 | 408 | promise.Cancel(); |
|
455 | 409 | } |
|
456 | 410 | ); |
|
411 | ||
|
412 | return default(T); | |
|
457 | 413 | }; |
|
458 | 414 | |
|
459 | 415 | Func<Exception,T> errorHandler; |
@@ -534,7 +490,10 namespace Implab { | |||
|
534 | 490 | var medium = new Promise<T>(this); |
|
535 | 491 | |
|
536 | 492 | AddHandler( |
|
537 |
x => |
|
|
493 | x => { | |
|
494 | handler(); | |
|
495 | return x; | |
|
496 | }, | |
|
538 | 497 | e => { |
|
539 | 498 | handler(); |
|
540 | 499 | throw new TransientPromiseException(e); |
@@ -600,16 +559,11 namespace Implab { | |||
|
600 | 559 | return Join(Timeout.Infinite); |
|
601 | 560 | } |
|
602 | 561 | |
|
603 |
void AddHandler( |
|
|
562 | void AddHandler<T2>(Func<T,T2> success, Func<Exception,T2> error, Action cancel, Promise<T2> medium, bool inc) { | |
|
604 | 563 | if (inc) |
|
605 | 564 | Interlocked.Increment(ref m_childrenCount); |
|
606 | 565 | |
|
607 |
|
|
|
608 | resultHandler = success, | |
|
609 | errorHandler = error, | |
|
610 | cancellHandler = cancel, | |
|
611 | medium = medium | |
|
612 | }; | |
|
566 | AbstractHandler handler = new HandlerDescriptor<T2>(success, error, cancel, medium); | |
|
613 | 567 | |
|
614 | 568 | bool queued; |
|
615 | 569 | |
@@ -631,7 +585,7 namespace Implab { | |||
|
631 | 585 | InvokeHandler(handler); |
|
632 | 586 | } |
|
633 | 587 | |
|
634 |
protected virtual void InvokeHandler(Handler |
|
|
588 | protected virtual void InvokeHandler(AbstractHandler handler) { | |
|
635 | 589 | switch (m_state) { |
|
636 | 590 | case SUCCEEDED_STATE: |
|
637 | 591 | handler.Resolve(m_result); |
@@ -649,7 +603,7 namespace Implab { | |||
|
649 | 603 | } |
|
650 | 604 | |
|
651 | 605 | void OnStateChanged() { |
|
652 |
Handler |
|
|
606 | AbstractHandler handler; | |
|
653 | 607 | while (m_handlers.TryDequeue(out handler)) |
|
654 | 608 | InvokeHandler(handler); |
|
655 | 609 | } |
@@ -688,16 +642,13 namespace Implab { | |||
|
688 | 642 | var dest = i; |
|
689 | 643 | |
|
690 | 644 | if (promises[i] != null) { |
|
691 |
promises[i]. |
|
|
645 | promises[i].On( | |
|
692 | 646 | x => { |
|
693 | 647 | result[dest] = x; |
|
694 | 648 | if (Interlocked.Decrement(ref pending) == 0) |
|
695 | 649 | promise.Resolve(result); |
|
696 | 650 | }, |
|
697 |
|
|
|
698 | promise.Reject(e); | |
|
699 | return default(T); | |
|
700 | } | |
|
651 | promise.Reject | |
|
701 | 652 | ); |
|
702 | 653 | } else { |
|
703 | 654 | if (Interlocked.Decrement(ref pending) == 0) |
@@ -776,7 +727,10 namespace Implab { | |||
|
776 | 727 | |
|
777 | 728 | IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) { |
|
778 | 729 | return Then( |
|
779 |
success != null ? new |
|
|
730 | success != null ? new Func<T,T>(x => { | |
|
731 | success(); | |
|
732 | return x; | |
|
733 | }) : null, | |
|
780 | 734 | error != null ? new Func<Exception,T>(e => { |
|
781 | 735 | error(e); |
|
782 | 736 | return default(T); |
@@ -787,7 +741,10 namespace Implab { | |||
|
787 | 741 | |
|
788 | 742 | IPromise IPromise.Then(Action success, Action<Exception> error) { |
|
789 | 743 | return Then( |
|
790 |
success != null ? new |
|
|
744 | success != null ? new Func<T,T>(x => { | |
|
745 | success(); | |
|
746 | return x; | |
|
747 | }) : null, | |
|
791 | 748 | error != null ? new Func<Exception,T>(e => { |
|
792 | 749 | error(e); |
|
793 | 750 | return default(T); |
@@ -797,7 +754,10 namespace Implab { | |||
|
797 | 754 | |
|
798 | 755 | IPromise IPromise.Then(Action success) { |
|
799 | 756 | Safe.ArgumentNotNull(success, "success"); |
|
800 |
return Then(x => |
|
|
757 | return Then(x => { | |
|
758 | success(); | |
|
759 | return x; | |
|
760 | }); | |
|
801 | 761 | } |
|
802 | 762 | |
|
803 | 763 | IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { |
@@ -809,9 +769,9 namespace Implab { | |||
|
809 | 769 | |
|
810 | 770 | var medium = new Promise<object>(this); |
|
811 | 771 | |
|
812 |
|
|
|
772 | Func<T,T> resultHandler = delegate { | |
|
813 | 773 | if (medium.IsCancelled) |
|
814 | return; | |
|
774 | return default(T); | |
|
815 | 775 | |
|
816 | 776 | var promise = chained(); |
|
817 | 777 | |
@@ -828,6 +788,8 namespace Implab { | |||
|
828 | 788 | if (promise.IsExclusive) |
|
829 | 789 | promise.Cancel(); |
|
830 | 790 | }); |
|
791 | ||
|
792 | return default(T); | |
|
831 | 793 | }; |
|
832 | 794 | |
|
833 | 795 | Func<Exception,T> errorHandler; |
@@ -14,7 +14,7 namespace Implab { | |||
|
14 | 14 | Safe.ArgumentNotNull(context, "context"); |
|
15 | 15 | m_context = context; |
|
16 | 16 | } |
|
17 |
protected override void InvokeHandler(Handler |
|
|
17 | protected override void InvokeHandler(AbstractHandler handler) { | |
|
18 | 18 | m_context.Post(x => base.InvokeHandler(handler),null); |
|
19 | 19 | } |
|
20 | 20 | } |
General Comments 0
You need to be logged in to leave comments.
Login now