Mercurial > pub > ImplabNet
annotate Implab/Promise.cs @ 33:b255e4aeef17
removed the reference to the parent from the promise object this allows
resolved promises to release parents and results they are holding.
Added complete set of operations to IPromiseBase interface
Subscribing to the cancellation event of the promise should not affect it's
IsExclusive property
More tests.
author | cin |
---|---|
date | Thu, 10 Apr 2014 02:39:29 +0400 |
parents | 8eca2652d2ff |
children | 653c4e04968b |
rev | line source |
---|---|
2 | 1 using System; |
2 using System.Collections.Generic; | |
3 using System.Reflection; | |
4 using System.Diagnostics; | |
5 using System.Threading; | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
6 using Implab.Parallels; |
2 | 7 |
8 namespace Implab { | |
9 | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
10 public delegate void ErrorHandler(Exception e); |
11 | 11 public delegate T ErrorHandler<out T>(Exception e); |
10 | 12 public delegate void ResultHandler<in T>(T result); |
13 public delegate TNew ResultMapper<in TSrc, out TNew>(TSrc result); | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
14 public delegate IPromise<TNew> ChainedOperation<in TSrc, TNew>(TSrc result); |
2 | 15 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
16 /// <summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
17 /// Класс для асинхронного получения результатов. Так называемое "обещание". |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
18 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
19 /// <typeparam name="T">Тип получаемого результата</typeparam> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
20 /// <remarks> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
21 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции, |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
22 /// клиент получив такое обещание может установить ряд обратных вызово для получения |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
23 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
24 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
25 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
26 /// данные события клиент должен использовать методы <c>Then</c>. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
27 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
28 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
29 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой), |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
30 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
31 /// выполнении обещания. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
32 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
33 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
34 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался, |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
35 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
36 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
37 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
38 /// обещания. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
39 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
40 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
41 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
42 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
43 /// использовать соответствующую форму методе <c>Then</c>. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
44 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
45 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
46 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
47 /// только инициатор обещания иначе могут возникнуть противоречия. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
48 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
49 /// </remarks> |
25 | 50 public class Promise<T> : IPromise<T> { |
2 | 51 |
28 | 52 protected struct HandlerDescriptor { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
53 public ResultHandler<T> resultHandler; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
54 public ErrorHandler errorHandler; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
55 public Action cancellHandler; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
56 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
57 public void Resolve(T result) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
58 if (resultHandler != null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
59 try { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
60 resultHandler(result); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
61 } catch (Exception e) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
62 Reject(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
63 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
64 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
65 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
66 public void Reject(Exception err) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
67 if (errorHandler != null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
68 try { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
69 errorHandler(err); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
70 } catch { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
71 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
72 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
73 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
74 public void Cancel() { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
75 if (cancellHandler != null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
76 try { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
77 cancellHandler(); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
78 } catch { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
79 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
80 } |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
81 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
82 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
83 const int UnresolvedSate = 0; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
84 const int TransitionalState = 1; |
25 | 85 const int SucceededState = 2; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
86 const int RejectedState = 3; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
87 const int CancelledState = 4; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
88 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
89 readonly bool m_cancellable; |
9 | 90 |
10 | 91 int m_childrenCount = 0; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
92 int m_state; |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
93 T m_result; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
94 Exception m_error; |
9 | 95 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
96 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>(); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
97 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
98 public Promise() { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
99 m_cancellable = true; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
100 } |
2 | 101 |
25 | 102 public Promise(IPromiseBase parent, bool cancellable) { |
7 | 103 m_cancellable = cancellable; |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
104 if (parent != null) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
105 AddHandler( |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
106 null, |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
107 null, |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
108 () => { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
109 if (parent.IsExclusive) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
110 parent.Cancel(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
111 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
112 ); |
10 | 113 } |
2 | 114 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
115 bool BeginTransit() { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
116 return UnresolvedSate == Interlocked.CompareExchange(ref m_state, TransitionalState, UnresolvedSate); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
117 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
118 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
119 void CompleteTransit(int state) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
120 if (TransitionalState != Interlocked.CompareExchange(ref m_state, state, TransitionalState)) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
121 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
122 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
123 |
25 | 124 void WaitTransition() { |
125 while (m_state == TransitionalState) { | |
126 /* noop */ | |
127 } | |
128 } | |
129 | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
130 public bool IsResolved { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
131 get { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
132 return m_state > 1; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
133 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
134 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
135 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
136 public bool IsCancelled { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
137 get { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
138 return m_state == CancelledState; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
139 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
140 } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
141 |
29 | 142 public Type PromiseType { |
143 get { return typeof(T); } | |
144 } | |
145 | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
146 /// <summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
147 /// Выполняет обещание, сообщая об успешном выполнении. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
148 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
149 /// <param name="result">Результат выполнения.</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
150 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
151 public void Resolve(T result) { |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
152 if (BeginTransit()) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
153 m_result = result; |
25 | 154 CompleteTransit(SucceededState); |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
155 OnStateChanged(); |
25 | 156 } else { |
157 WaitTransition(); | |
158 if (m_state != CancelledState) | |
159 throw new InvalidOperationException("The promise is already resolved"); | |
160 } | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
161 } |
2 | 162 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
163 /// <summary> |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
164 /// Выполняет обещание, сообщая об успешном выполнении. Результатом выполнения будет пустое значения. |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
165 /// </summary> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
166 /// <remarks> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
167 /// Данный вариант удобен в случаях, когда интересен факт выполнения операции, нежели полученное значение. |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
168 /// </remarks> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
169 public void Resolve() { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
170 Resolve(default(T)); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
171 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
172 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
173 /// <summary> |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
174 /// Выполняет обещание, сообщая об ошибке |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
175 /// </summary> |
16 | 176 /// <remarks> |
177 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | |
178 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | |
179 /// будут проигнорированы. | |
180 /// </remarks> | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
181 /// <param name="error">Исключение возникшее при выполнении операции</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
182 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
183 public void Reject(Exception error) { |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
184 if (BeginTransit()) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
185 m_error = error; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
186 CompleteTransit(RejectedState); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
187 OnStateChanged(); |
25 | 188 } else { |
189 WaitTransition(); | |
190 if (m_state == SucceededState) | |
191 throw new InvalidOperationException("The promise is already resolved"); | |
192 } | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
193 } |
2 | 194 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
195 /// <summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
196 /// Отменяет операцию, если это возможно. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
197 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
198 /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
199 public bool Cancel() { |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
200 if (BeginTransit()) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
201 CompleteTransit(CancelledState); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
202 OnStateChanged(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
203 return true; |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
204 } else { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
205 return false; |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
206 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
207 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
208 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
209 // сделано для возвращаемого типа void |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
210 protected void InternalCancel() { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
211 Cancel(); |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
212 } |
2 | 213 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
214 /// <summary> |
11 | 215 /// Adds new handlers to this promise. |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
216 /// </summary> |
11 | 217 /// <param name="success">The handler of the successfully completed operation. |
218 /// This handler will recieve an operation result as a parameter.</param> | |
219 /// <param name="error">Handles an exception that may occur during the operation.</param> | |
220 /// <returns>The new promise chained to this one.</returns> | |
26 | 221 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler error) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
222 if (success == null && error == null) |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
223 return this; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
224 |
11 | 225 var medium = new Promise<T>(this, true); |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
226 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
227 ResultHandler<T> resultHandler; |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
228 if (success != null) |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
229 resultHandler = x => { |
10 | 230 success(x); |
231 medium.Resolve(x); | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
232 }; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
233 else |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
234 resultHandler = medium.Resolve; |
2 | 235 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
236 ErrorHandler errorHandler; |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
237 if (error != null) |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
238 errorHandler = x => { |
25 | 239 // несмотря на то, что обработчик ошибки вызывается безопасно, |
240 // т.е. возникшие в нем ошибки будут подавлены, нам нужно | |
241 // гарантировать, что ошибка будет передана дальше по цепочке обещаний | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
242 try { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
243 error(x); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
244 } catch { } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
245 medium.Reject(x); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
246 }; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
247 else |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
248 errorHandler = medium.Reject; |
2 | 249 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
250 AddHandler(resultHandler, errorHandler, medium.InternalCancel); |
2 | 251 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
252 return medium; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
253 } |
2 | 254 |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
255 public IPromiseBase Then(Action success, ErrorHandler error) { |
26 | 256 return Then(x => success(), error); |
257 } | |
258 | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
259 public IPromiseBase Then(Action success) { |
32 | 260 return Then(x => success()); |
26 | 261 } |
262 | |
11 | 263 /// <summary> |
264 /// Adds new handlers to this promise. | |
265 /// </summary> | |
266 /// <param name="success">The handler of the successfully completed operation. | |
267 /// This handler will recieve an operation result as a parameter.</param> | |
268 /// <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> | |
269 /// <returns>The new promise chained to this one.</returns> | |
26 | 270 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) { |
11 | 271 if (success == null && error == null) |
272 return this; | |
273 | |
274 var medium = new Promise<T>(this, true); | |
275 | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
276 ResultHandler<T> resultHandler; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
277 ErrorHandler errorHandler; |
11 | 278 |
279 if (success != null) | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
280 resultHandler = x => { |
11 | 281 success(x); |
282 medium.Resolve(x); | |
283 }; | |
284 else | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
285 resultHandler = medium.Resolve; |
11 | 286 |
287 if (error != null) | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
288 errorHandler = x => { |
11 | 289 try { |
290 medium.Resolve(error(x)); | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
291 } catch (Exception e) { |
25 | 292 medium.Reject(e); |
293 } | |
11 | 294 }; |
295 else | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
296 errorHandler = medium.Reject; |
11 | 297 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
298 AddHandler(resultHandler, errorHandler, medium.InternalCancel); |
11 | 299 |
300 return medium; | |
301 } | |
302 | |
303 | |
26 | 304 public IPromise<T> Then(ResultHandler<T> success) { |
11 | 305 if (success == null) |
306 return this; | |
307 | |
308 var medium = new Promise<T>(this, true); | |
309 | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
310 ResultHandler<T> resultHandler; |
25 | 311 |
11 | 312 if (success != null) |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
313 resultHandler = x => { |
11 | 314 success(x); |
315 medium.Resolve(x); | |
316 }; | |
317 else | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
318 resultHandler = medium.Resolve; |
11 | 319 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
320 AddHandler(resultHandler, medium.Reject, medium.InternalCancel); |
11 | 321 |
322 return medium; | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
323 } |
2 | 324 |
26 | 325 public IPromise<T> Error(ErrorHandler error) { |
326 return Then((ResultHandler<T>)null, error); | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
327 } |
2 | 328 |
11 | 329 /// <summary> |
330 /// Handles error and allows to keep the promise. | |
331 /// </summary> | |
332 /// <remarks> | |
333 /// If the specified handler throws an exception, this exception will be used to reject the promise. | |
334 /// </remarks> | |
335 /// <param name="handler">The error handler which returns the result of the promise.</param> | |
336 /// <returns>New promise.</returns> | |
26 | 337 public IPromise<T> Error(ErrorHandler<T> handler) { |
11 | 338 if (handler == null) |
339 return this; | |
340 | |
341 var medium = new Promise<T>(this, true); | |
342 | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
343 AddHandler( |
27 | 344 x => medium.Resolve(x), |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
345 e => { |
11 | 346 try { |
347 medium.Resolve(handler(e)); | |
348 } catch (Exception e2) { | |
349 medium.Reject(e2); | |
350 } | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
351 }, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
352 medium.InternalCancel |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
353 ); |
11 | 354 |
355 return medium; | |
356 } | |
357 | |
26 | 358 public IPromise<T> Anyway(Action handler) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
359 if (handler == null) |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
360 return this; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
361 |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
362 var medium = new Promise<T>(this,true); |
2 | 363 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
364 AddHandler( |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
365 x => { |
10 | 366 // to avoid handler being called multiple times we handle exception by ourselfs |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
367 try { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
368 handler(); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
369 medium.Resolve(x); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
370 } catch (Exception e) { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
371 medium.Reject(e); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
372 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
373 }, |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
374 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
375 e => { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
376 try { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
377 handler(); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
378 } catch { } |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
379 medium.Reject(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
380 }, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
381 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
382 medium.InternalCancel |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
383 ); |
2 | 384 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
385 return medium; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
386 } |
2 | 387 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
388 /// <summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
389 /// Позволяет преобразовать результат выполения операции к новому типу. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
390 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
391 /// <typeparam name="TNew">Новый тип результата.</typeparam> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
392 /// <param name="mapper">Преобразование результата к новому типу.</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
393 /// <param name="error">Обработчик ошибки. Данный обработчик получит |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
394 /// исключение возникшее при выполнении операции.</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
395 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns> |
26 | 396 public IPromise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler error) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
397 if (mapper == null) |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
398 throw new ArgumentNullException("mapper"); |
2 | 399 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
400 // создаем прицепленное обещание |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
401 var chained = new Promise<TNew>(this,true); |
2 | 402 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
403 ResultHandler<T> resultHandler = result => chained.Resolve(mapper(result)); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
404 ErrorHandler errorHandler = delegate(Exception e) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
405 if (error != null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
406 try { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
407 error(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
408 } catch { } |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
409 // в случае ошибки нужно передать исключение дальше по цепочке |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
410 chained.Reject(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
411 }; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
412 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
413 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
414 AddHandler( |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
415 resultHandler, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
416 errorHandler, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
417 chained.InternalCancel |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
418 ); |
2 | 419 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
420 return chained; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
421 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
422 |
26 | 423 public IPromise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
424 return Map(mapper, null); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
425 } |
2 | 426 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
427 /// <summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
428 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
429 /// выполнения текущей, а результат текущей операции может быть использован для инициализации |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
430 /// новой операции. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
431 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
432 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
433 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
434 /// <param name="error">Обработчик ошибки. Данный обработчик получит |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
435 /// исключение возникшее при выполнении текуещй операции.</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
436 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns> |
26 | 437 public IPromise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler error) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
438 |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
439 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
440 // создать посредника, к которому будут подвызяваться следующие обработчики. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
441 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
442 // передать через него результаты работы. |
10 | 443 var medium = new Promise<TNew>(this, true); |
2 | 444 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
445 ResultHandler<T> resultHandler = delegate(T result) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
446 if (medium.IsCancelled) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
447 return; |
10 | 448 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
449 var promise = chained(result); |
10 | 450 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
451 promise.Then( |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
452 x => medium.Resolve(x), |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
453 e => medium.Reject(e) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
454 ); |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
455 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
456 // notify chained operation that it's not needed anymore |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
457 // порядок вызова Then, Cancelled важен, поскольку от этого |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
458 // зависит IsExclusive |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
459 medium.Cancelled(() => { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
460 if(promise.IsExclusive) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
461 promise.Cancel(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
462 }); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
463 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
464 // внешняя отмена связанной операции рассматривается как ошибка |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
465 promise.Cancelled(() => medium.Reject(new OperationCanceledException())); |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
466 }; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
467 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
468 ErrorHandler errorHandler = delegate(Exception e) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
469 if (error != null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
470 error(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
471 // в случае ошибки нужно передать исключение дальше по цепочке |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
472 medium.Reject(e); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
473 }; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
474 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
475 AddHandler( |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
476 resultHandler, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
477 errorHandler, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
478 medium.InternalCancel |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
479 ); |
2 | 480 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
481 return medium; |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
482 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
483 |
26 | 484 public IPromise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained) { |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
485 return Chain(chained, null); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
486 } |
2 | 487 |
26 | 488 public IPromise<T> Cancelled(Action handler) { |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
489 AddHandler(null, null, handler); |
10 | 490 return this; |
491 } | |
492 | |
25 | 493 /// <summary> |
494 /// Adds the specified handler for all cases (success, error, cancel) | |
495 /// </summary> | |
496 /// <param name="handler">The handler that will be called anyway</param> | |
497 /// <returns>self</returns> | |
26 | 498 public IPromise<T> Finally(Action handler) { |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
499 if (handler == null) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
500 throw new ArgumentNullException("handler"); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
501 AddHandler( |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
502 x => handler(), |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
503 e => handler(), |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
504 handler |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
505 ); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
506 return this; |
10 | 507 } |
508 | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
509 /// <summary> |
29 | 510 /// Преобразует результат обещания к нужному типу |
511 /// </summary> | |
512 /// <typeparam name="T2"></typeparam> | |
513 /// <returns></returns> | |
514 public IPromise<T2> Cast<T2>() { | |
515 return Map(x => (T2)(object)x, null); | |
516 } | |
517 | |
518 /// <summary> | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
519 /// Дожидается отложенного обещания и в случае успеха, возвращает |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
520 /// его, результат, в противном случае бросает исключение. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
521 /// </summary> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
522 /// <remarks> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
523 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
524 /// Если ожидание обещания было прервано по таймауту, это не значит, |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
525 /// что обещание было отменено или что-то в этом роде, это только |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
526 /// означает, что мы его не дождались, однако все зарегистрированные |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
527 /// обработчики, как были так остались и они будут вызваны, когда |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
528 /// обещание будет выполнено. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
529 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
530 /// <para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
531 /// Такое поведение вполне оправдано поскольку таймаут может истечь |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
532 /// в тот момент, когда началась обработка цепочки обработчиков, и |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
533 /// к тому же текущее обещание может стоять в цепочке обещаний и его |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
534 /// отклонение может привести к непрогнозируемому результату. |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
535 /// </para> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
536 /// </remarks> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
537 /// <param name="timeout">Время ожидания</param> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
538 /// <returns>Результат выполнения обещания</returns> |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
539 public T Join(int timeout) { |
10 | 540 var evt = new ManualResetEvent(false); |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
541 Anyway(() => evt.Set()); |
10 | 542 Cancelled(() => evt.Set()); |
2 | 543 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
544 if (!evt.WaitOne(timeout, true)) |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
545 throw new TimeoutException(); |
2 | 546 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
547 switch (m_state) { |
25 | 548 case SucceededState: |
10 | 549 return m_result; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
550 case CancelledState: |
10 | 551 throw new OperationCanceledException(); |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
552 case RejectedState: |
10 | 553 throw new TargetInvocationException(m_error); |
554 default: | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
555 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); |
10 | 556 } |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
557 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
558 |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
559 public T Join() { |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
560 return Join(Timeout.Infinite); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
561 } |
2 | 562 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
563 void AddHandler(ResultHandler<T> success, ErrorHandler error, Action cancel) { |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
564 if (success != null || error != null) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
565 Interlocked.Increment(ref m_childrenCount); |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
566 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
567 HandlerDescriptor handler = new HandlerDescriptor { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
568 resultHandler = success, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
569 errorHandler = error, |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
570 cancellHandler = cancel |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
571 }; |
2 | 572 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
573 bool queued; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
574 |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
575 if (!IsResolved) { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
576 m_handlers.Enqueue(handler); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
577 queued = true; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
578 } else { |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
579 // the promise is in resolved state, just invoke the handled with minimum overhead |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
580 queued = false; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
581 InvokeHandler(handler); |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
582 } |
2 | 583 |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
584 if (queued && IsResolved && m_handlers.TryDequeue(out handler)) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
585 // if the promise have been resolved while we was adding handler to the queue |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
586 // we can't guarantee that someone is still processing it |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
587 // therefore we will fetch a handler from the queue and execute it |
27 | 588 // note that fetched handler may be not the one that we have added |
589 // even we can fetch no handlers at all :) | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
590 InvokeHandler(handler); |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
591 } |
2 | 592 |
27 | 593 protected virtual void InvokeHandler(HandlerDescriptor handler) { |
10 | 594 switch (m_state) { |
25 | 595 case SucceededState: |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
596 handler.Resolve(m_result); |
10 | 597 break; |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
598 case RejectedState: |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
599 handler.Reject(m_error); |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
600 break; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
601 case CancelledState: |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
602 handler.Cancel(); |
10 | 603 break; |
604 default: | |
605 // do nothing | |
606 return; | |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
607 } |
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
608 } |
2 | 609 |
11 | 610 protected virtual void OnStateChanged() { |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
611 HandlerDescriptor handler; |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
612 while (m_handlers.TryDequeue(out handler)) |
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
613 InvokeHandler(handler); |
11 | 614 } |
615 | |
9 | 616 public bool IsExclusive { |
617 get { | |
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
16
diff
changeset
|
618 return m_childrenCount <= 1; |
9 | 619 } |
620 } | |
621 | |
25 | 622 /// <summary> |
623 /// Объединяет несколько обещаний в одно, результатом которого является массив результатов других обещаний. | |
624 /// Если хотябы одно из переданных обещаний не будет выполнено, то новое обещение тоже не будет выполнено. | |
625 /// При отмене нового обещания, переданные обещания также будут отменены, если никто больше на них не подписан. | |
626 /// </summary> | |
627 /// <param name="promises">Список обещаний. Если список пустой, то результирующее обещание возвращается уже выполненным.</param> | |
628 /// <returns>Обещание объединяющее в себе результат переданных обещаний.</returns> | |
629 /// <exception cref="ArgumentNullException"><paramref name="promises"/> не может быть null</exception> | |
30 | 630 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) { |
25 | 631 if (promises == null) |
632 throw new ArgumentNullException(); | |
633 | |
634 // создаем аккумулятор для результатов и результирующее обещание | |
635 var result = new T[promises.Count]; | |
636 var promise = new Promise<T[]>(); | |
637 | |
638 // special case | |
639 if (promises.Count == 0) { | |
640 promise.Resolve(result); | |
641 return promise; | |
642 } | |
643 | |
644 int pending = promises.Count; | |
645 | |
646 for (int i = 0; i < promises.Count; i++) { | |
647 var dest = i; | |
648 | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
649 if (promises[i] != null) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
650 promises[i].Then( |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
651 x => { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
652 result[dest] = x; |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
653 if (Interlocked.Decrement(ref pending) == 0) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
654 promise.Resolve(result); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
655 }, |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
656 e => promise.Reject(e) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
657 ); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
658 } else { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
659 if (Interlocked.Decrement(ref pending) == 0) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
660 promise.Resolve(result); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
661 } |
25 | 662 } |
663 | |
664 promise.Cancelled( | |
665 () => { | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
666 foreach (var d in promises) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
667 if (d != null && d.IsExclusive) |
25 | 668 d.Cancel(); |
669 } | |
670 ); | |
671 | |
672 return promise; | |
673 } | |
674 | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
675 /// <summary> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
676 /// Объединяет несколько обещаний в одно. Результирующее обещание будет выполнено при |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
677 /// выполнении всех указанных обещаний. При этом возвращаемые значения первичных обещаний |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
678 /// игнорируются. |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
679 /// </summary> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
680 /// <param name="promises">Коллекция первичных обещаний, которые будут объеденены в одно.</param> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
681 /// <returns>Новое обещание, объединяющее в себе переданные.</returns> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
682 /// <remarks> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
683 /// Если в коллекции встречаюься <c>null</c>, то они воспринимаются как выполненные обещания. |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
684 /// </remarks> |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
685 public static IPromiseBase CreateComposite(ICollection<IPromiseBase> promises) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
686 if (promises == null) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
687 throw new ArgumentNullException(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
688 if (promises.Count == 0) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
689 return Promise<object>.ResultToPromise(null); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
690 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
691 int countdown = promises.Count; |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
692 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
693 var result = new Promise<object>(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
694 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
695 foreach (var d in promises) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
696 if (d == null) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
697 if (Interlocked.Decrement(ref countdown) == 0) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
698 result.Resolve(null); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
699 } else { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
700 d.Then(() => { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
701 if (Interlocked.Decrement(ref countdown) == 0) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
702 result.Resolve(null); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
703 }); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
704 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
705 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
706 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
707 result.Cancelled(() => { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
708 foreach (var d in promises) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
709 if (d != null && d.IsExclusive) |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
710 d.Cancel(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
711 }); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
712 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
713 return result; |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
714 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
715 |
25 | 716 public static Promise<T> ResultToPromise(T result) { |
717 var p = new Promise<T>(); | |
718 p.Resolve(result); | |
719 return p; | |
720 } | |
721 | |
722 public static Promise<T> ExceptionToPromise(Exception error) { | |
723 if (error == null) | |
724 throw new ArgumentNullException(); | |
725 | |
726 var p = new Promise<T>(); | |
727 p.Reject(error); | |
728 return p; | |
729 } | |
730 | |
33
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
731 #region IPromiseBase explicit implementation |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
732 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
733 IPromiseBase IPromiseBase.Error(ErrorHandler error) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
734 return Error(error); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
735 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
736 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
737 IPromiseBase IPromiseBase.Anyway(Action handler) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
738 return Anyway(handler); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
739 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
740 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
741 IPromiseBase IPromiseBase.Finally(Action handler) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
742 return Finally(handler); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
743 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
744 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
745 IPromiseBase IPromiseBase.Cancelled(Action handler) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
746 return Cancelled(handler); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
747 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
748 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
749 void IPromiseBase.Join() { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
750 Join(); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
751 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
752 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
753 void IPromiseBase.Join(int timeout) { |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
754 Join(timeout); |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
755 } |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
756 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
757 #endregion |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
758 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
759 |
b255e4aeef17
removed the reference to the parent from the promise object this allows
cin
parents:
32
diff
changeset
|
760 |
6
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
cin
parents:
2
diff
changeset
|
761 } |
2 | 762 } |