Mercurial > pub > ImplabNet
comparison Implab/Promise.cs @ 11:6ec82bf68c8e promises
refactoring
author | cin |
---|---|
date | Tue, 05 Nov 2013 01:09:58 +0400 |
parents | aa33d0bb8c0c |
children | e943453e5039 |
comparison
equal
deleted
inserted
replaced
10:aa33d0bb8c0c | 11:6ec82bf68c8e |
---|---|
5 using System.Threading; | 5 using System.Threading; |
6 | 6 |
7 namespace Implab { | 7 namespace Implab { |
8 | 8 |
9 public delegate void ErrorHandler(Exception e); | 9 public delegate void ErrorHandler(Exception e); |
10 | 10 public delegate T ErrorHandler<out T>(Exception e); |
11 public delegate void ResultHandler<in T>(T result); | 11 public delegate void ResultHandler<in T>(T result); |
12 public delegate TNew ResultMapper<in TSrc, out TNew>(TSrc result); | 12 public delegate TNew ResultMapper<in TSrc, out TNew>(TSrc result); |
13 public delegate Promise<TNew> ChainedOperation<in TSrc, TNew>(TSrc result); | 13 public delegate Promise<TNew> ChainedOperation<in TSrc, TNew>(TSrc result); |
14 | 14 |
15 /// <summary> | 15 /// <summary> |
124 /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns> | 124 /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns> |
125 public bool Cancel() { | 125 public bool Cancel() { |
126 return Cancel(true); | 126 return Cancel(true); |
127 } | 127 } |
128 | 128 |
129 /// <summary> | |
130 /// Adds new handlers to this promise. | |
131 /// </summary> | |
132 /// <param name="success">The handler of the successfully completed operation. | |
133 /// This handler will recieve an operation result as a parameter.</param> | |
134 /// <param name="error">Handles an exception that may occur during the operation.</param> | |
135 /// <returns>The new promise chained to this one.</returns> | |
136 public Promise<T> Then(ResultHandler<T> success, ErrorHandler error) { | |
137 if (success == null && error == null) | |
138 return this; | |
139 | |
140 var medium = new Promise<T>(this, true); | |
141 | |
142 var handlerInfo = new ResultHandlerInfo(); | |
143 | |
144 if (success != null) | |
145 handlerInfo.resultHandler = x => { | |
146 success(x); | |
147 medium.Resolve(x); | |
148 }; | |
149 else | |
150 handlerInfo.resultHandler = medium.Resolve; | |
151 | |
152 if (error != null) | |
153 handlerInfo.errorHandler = x => { | |
154 try { | |
155 error(x); | |
156 } catch { } | |
157 medium.Reject(x); | |
158 }; | |
159 else | |
160 handlerInfo.errorHandler = medium.Reject; | |
161 | |
162 AddHandler(handlerInfo); | |
163 | |
164 return medium; | |
165 } | |
166 | |
167 /// <summary> | |
168 /// Adds new handlers to this promise. | |
169 /// </summary> | |
170 /// <param name="success">The handler of the successfully completed operation. | |
171 /// This handler will recieve an operation result as a parameter.</param> | |
172 /// <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> | |
173 /// <returns>The new promise chained to this one.</returns> | |
174 public Promise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) { | |
175 if (success == null && error == null) | |
176 return this; | |
177 | |
178 var medium = new Promise<T>(this, true); | |
179 | |
180 var handlerInfo = new ResultHandlerInfo(); | |
181 | |
182 if (success != null) | |
183 handlerInfo.resultHandler = x => { | |
184 success(x); | |
185 medium.Resolve(x); | |
186 }; | |
187 else | |
188 handlerInfo.resultHandler = medium.Resolve; | |
189 | |
190 if (error != null) | |
191 handlerInfo.errorHandler = x => { | |
192 try { | |
193 medium.Resolve(error(x)); | |
194 } catch { } | |
195 medium.Reject(x); | |
196 }; | |
197 else | |
198 handlerInfo.errorHandler = medium.Reject; | |
199 | |
200 AddHandler(handlerInfo); | |
201 | |
202 return medium; | |
203 } | |
204 | |
205 | |
206 public Promise<T> Then(ResultHandler<T> success) { | |
207 if (success == null) | |
208 return this; | |
209 | |
210 var medium = new Promise<T>(this, true); | |
211 | |
212 var handlerInfo = new ResultHandlerInfo(); | |
213 | |
214 if (success != null) | |
215 handlerInfo.resultHandler = x => { | |
216 success(x); | |
217 medium.Resolve(x); | |
218 }; | |
219 else | |
220 handlerInfo.resultHandler = medium.Resolve; | |
221 | |
222 handlerInfo.errorHandler = medium.Reject; | |
223 | |
224 AddHandler(handlerInfo); | |
225 | |
226 return medium; | |
227 } | |
228 | |
229 public Promise<T> Error(ErrorHandler error) { | |
230 return Then(null, error); | |
231 } | |
232 | |
233 /// <summary> | |
234 /// Handles error and allows to keep the promise. | |
235 /// </summary> | |
236 /// <remarks> | |
237 /// If the specified handler throws an exception, this exception will be used to reject the promise. | |
238 /// </remarks> | |
239 /// <param name="handler">The error handler which returns the result of the promise.</param> | |
240 /// <returns>New promise.</returns> | |
241 public Promise<T> Error(ErrorHandler<T> handler) { | |
242 if (handler == null) | |
243 return this; | |
244 | |
245 var medium = new Promise<T>(this, true); | |
246 | |
247 AddHandler(new ResultHandlerInfo { | |
248 errorHandler = e => { | |
249 try { | |
250 medium.Resolve(handler(e)); | |
251 } catch (Exception e2) { | |
252 medium.Reject(e2); | |
253 } | |
254 } | |
255 }); | |
256 | |
257 return medium; | |
258 } | |
259 | |
260 public Promise<T> Anyway(Action handler) { | |
261 if (handler == null) | |
262 return this; | |
263 | |
264 var medium = new Promise<T>(); | |
265 | |
266 AddHandler(new ResultHandlerInfo { | |
267 resultHandler = x => { | |
268 // to avoid handler being called multiple times we handle exception by ourselfs | |
269 try { | |
270 handler(); | |
271 medium.Resolve(x); | |
272 } catch (Exception e) { | |
273 medium.Reject(e); | |
274 } | |
275 }, | |
276 errorHandler = x => { | |
277 try { | |
278 handler(); | |
279 } catch { } | |
280 medium.Reject(x); | |
281 } | |
282 }); | |
283 | |
284 return medium; | |
285 } | |
286 | |
287 /// <summary> | |
288 /// Позволяет преобразовать результат выполения операции к новому типу. | |
289 /// </summary> | |
290 /// <typeparam name="TNew">Новый тип результата.</typeparam> | |
291 /// <param name="mapper">Преобразование результата к новому типу.</param> | |
292 /// <param name="error">Обработчик ошибки. Данный обработчик получит | |
293 /// исключение возникшее при выполнении операции.</param> | |
294 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns> | |
295 public Promise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler error) { | |
296 if (mapper == null) | |
297 throw new ArgumentNullException("mapper"); | |
298 | |
299 // создаем прицепленное обещание | |
300 var chained = new Promise<TNew>(); | |
301 | |
302 AddHandler(new ResultHandlerInfo() { | |
303 resultHandler = result => chained.Resolve(mapper(result)), | |
304 errorHandler = delegate(Exception e) { | |
305 if (error != null) | |
306 try { | |
307 error(e); | |
308 } catch { } | |
309 // в случае ошибки нужно передать исключение дальше по цепочке | |
310 chained.Reject(e); | |
311 } | |
312 }); | |
313 | |
314 return chained; | |
315 } | |
316 | |
317 public Promise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper) { | |
318 return Map(mapper, null); | |
319 } | |
320 | |
321 /// <summary> | |
322 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после | |
323 /// выполнения текущей, а результат текущей операции может быть использован для инициализации | |
324 /// новой операции. | |
325 /// </summary> | |
326 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam> | |
327 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param> | |
328 /// <param name="error">Обработчик ошибки. Данный обработчик получит | |
329 /// исключение возникшее при выполнении текуещй операции.</param> | |
330 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns> | |
331 public Promise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler error) { | |
332 | |
333 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно | |
334 // создать посредника, к которому будут подвызяваться следующие обработчики. | |
335 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы | |
336 // передать через него результаты работы. | |
337 var medium = new Promise<TNew>(this, true); | |
338 | |
339 AddHandler(new ResultHandlerInfo { | |
340 resultHandler = delegate(T result) { | |
341 if (medium.State == PromiseState.Cancelled) | |
342 return; | |
343 | |
344 var promise = chained(result); | |
345 | |
346 // notify chained operation that it's not needed | |
347 medium.Cancelled(() => promise.Cancel()); | |
348 promise.Then( | |
349 x => medium.Resolve(x), | |
350 e => medium.Reject(e) | |
351 ); | |
352 }, | |
353 errorHandler = delegate(Exception e) { | |
354 if (error != null) | |
355 error(e); | |
356 // в случае ошибки нужно передать исключение дальше по цепочке | |
357 medium.Reject(e); | |
358 } | |
359 }); | |
360 | |
361 return medium; | |
362 } | |
363 | |
364 public Promise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained) { | |
365 return Chain(chained, null); | |
366 } | |
367 | |
368 public Promise<T> Cancelled(Action handler) { | |
369 if (handler == null) | |
370 return this; | |
371 lock (m_lock) { | |
372 if (m_state == PromiseState.Unresolved) | |
373 m_cancelHandlers.AddLast(handler); | |
374 else if (m_state == PromiseState.Cancelled) | |
375 handler(); | |
376 } | |
377 return this; | |
378 } | |
379 | |
380 public void HandleCancelled(Action handler) { | |
381 Cancelled(handler); | |
382 } | |
383 | |
384 /// <summary> | |
385 /// Дожидается отложенного обещания и в случае успеха, возвращает | |
386 /// его, результат, в противном случае бросает исключение. | |
387 /// </summary> | |
388 /// <remarks> | |
389 /// <para> | |
390 /// Если ожидание обещания было прервано по таймауту, это не значит, | |
391 /// что обещание было отменено или что-то в этом роде, это только | |
392 /// означает, что мы его не дождались, однако все зарегистрированные | |
393 /// обработчики, как были так остались и они будут вызваны, когда | |
394 /// обещание будет выполнено. | |
395 /// </para> | |
396 /// <para> | |
397 /// Такое поведение вполне оправдано поскольку таймаут может истечь | |
398 /// в тот момент, когда началась обработка цепочки обработчиков, и | |
399 /// к тому же текущее обещание может стоять в цепочке обещаний и его | |
400 /// отклонение может привести к непрогнозируемому результату. | |
401 /// </para> | |
402 /// </remarks> | |
403 /// <param name="timeout">Время ожидания</param> | |
404 /// <returns>Результат выполнения обещания</returns> | |
405 public T Join(int timeout) { | |
406 var evt = new ManualResetEvent(false); | |
407 Anyway(() => evt.Set()); | |
408 Cancelled(() => evt.Set()); | |
409 | |
410 if (!evt.WaitOne(timeout, true)) | |
411 throw new TimeoutException(); | |
412 | |
413 switch (State) { | |
414 case PromiseState.Resolved: | |
415 return m_result; | |
416 case PromiseState.Cancelled: | |
417 throw new OperationCanceledException(); | |
418 case PromiseState.Rejected: | |
419 throw new TargetInvocationException(m_error); | |
420 default: | |
421 throw new ApplicationException(String.Format("Invalid promise state {0}", State)); | |
422 } | |
423 } | |
424 | |
425 public T Join() { | |
426 return Join(Timeout.Infinite); | |
427 } | |
428 | |
429 void AddHandler(ResultHandlerInfo handler) { | |
430 bool invokeRequired = false; | |
431 | |
432 lock (m_lock) { | |
433 m_childrenCount++; | |
434 if (m_state == PromiseState.Unresolved) { | |
435 m_resultHandlers.AddLast(handler); | |
436 } else | |
437 invokeRequired = true; | |
438 } | |
439 | |
440 // обработчики не должны блокировать сам объект | |
441 if (invokeRequired) | |
442 InvokeHandler(handler); | |
443 } | |
444 | |
445 void InvokeHandler(ResultHandlerInfo handler) { | |
446 switch (m_state) { | |
447 case PromiseState.Resolved: | |
448 try { | |
449 if (handler.resultHandler != null) | |
450 handler.resultHandler(m_result); | |
451 } catch (Exception e) { | |
452 try { | |
453 if (handler.errorHandler != null) | |
454 handler.errorHandler(e); | |
455 } catch { } | |
456 } | |
457 break; | |
458 case PromiseState.Rejected: | |
459 try { | |
460 if (handler.errorHandler != null) | |
461 handler.errorHandler(m_error); | |
462 } catch { } | |
463 break; | |
464 default: | |
465 // do nothing | |
466 return; | |
467 } | |
468 } | |
469 | |
129 protected virtual void OnStateChanged() { | 470 protected virtual void OnStateChanged() { |
130 switch (m_state) { | 471 switch (m_state) { |
131 case PromiseState.Resolved: | 472 case PromiseState.Resolved: |
132 foreach (var resultHandlerInfo in m_resultHandlers) | 473 foreach (var resultHandlerInfo in m_resultHandlers) |
133 try { | 474 try { |
157 | 498 |
158 m_resultHandlers = null; | 499 m_resultHandlers = null; |
159 m_cancelHandlers = null; | 500 m_cancelHandlers = null; |
160 } | 501 } |
161 | 502 |
162 /// <summary> | |
163 /// Добавляет обработчики событий выполнения обещания. | |
164 /// </summary> | |
165 /// <param name="success">Обработчик успешного выполнения обещания. | |
166 /// Данному обработчику будет передан результат выполнения операции.</param> | |
167 /// <param name="error">Обработчик ошибки. Данный обработчик получит | |
168 /// исключение возникшее при выполнении операции.</param> | |
169 /// <returns>Само обещание</returns> | |
170 public Promise<T> Then(ResultHandler<T> success, ErrorHandler error) { | |
171 if (success == null && error == null) | |
172 return this; | |
173 | |
174 var medium = new Promise<T>(); | |
175 | |
176 var handlerInfo = new ResultHandlerInfo(); | |
177 | |
178 if (success != null) | |
179 handlerInfo.resultHandler = x => { | |
180 success(x); | |
181 medium.Resolve(x); | |
182 }; | |
183 else | |
184 handlerInfo.resultHandler = medium.Resolve; | |
185 | |
186 if (error != null) | |
187 handlerInfo.errorHandler = x => { | |
188 try { | |
189 error(x); | |
190 } catch { } | |
191 medium.Reject(x); | |
192 }; | |
193 else | |
194 handlerInfo.errorHandler = medium.Reject; | |
195 | |
196 AddHandler(handlerInfo); | |
197 | |
198 return medium; | |
199 } | |
200 | |
201 public Promise<T> Then(ResultHandler<T> success) { | |
202 return Then(success, null); | |
203 } | |
204 | |
205 public Promise<T> Error(ErrorHandler error) { | |
206 return Then(null, error); | |
207 } | |
208 | |
209 public Promise<T> Anyway(Action handler) { | |
210 if (handler == null) | |
211 return this; | |
212 | |
213 var medium = new Promise<T>(); | |
214 | |
215 AddHandler(new ResultHandlerInfo { | |
216 resultHandler = x => { | |
217 // to avoid handler being called multiple times we handle exception by ourselfs | |
218 try { | |
219 handler(); | |
220 medium.Resolve(x); | |
221 } catch (Exception e) { | |
222 medium.Reject(e); | |
223 } | |
224 }, | |
225 errorHandler = x => { | |
226 try { | |
227 handler(); | |
228 } catch { } | |
229 medium.Reject(x); | |
230 } | |
231 }); | |
232 | |
233 return medium; | |
234 } | |
235 | |
236 /// <summary> | |
237 /// Позволяет преобразовать результат выполения операции к новому типу. | |
238 /// </summary> | |
239 /// <typeparam name="TNew">Новый тип результата.</typeparam> | |
240 /// <param name="mapper">Преобразование результата к новому типу.</param> | |
241 /// <param name="error">Обработчик ошибки. Данный обработчик получит | |
242 /// исключение возникшее при выполнении операции.</param> | |
243 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns> | |
244 public Promise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler error) { | |
245 if (mapper == null) | |
246 throw new ArgumentNullException("mapper"); | |
247 | |
248 // создаем прицепленное обещание | |
249 var chained = new Promise<TNew>(); | |
250 | |
251 AddHandler(new ResultHandlerInfo() { | |
252 resultHandler = result => chained.Resolve(mapper(result)), | |
253 errorHandler = delegate(Exception e) { | |
254 if (error != null) | |
255 try { | |
256 error(e); | |
257 } catch { } | |
258 // в случае ошибки нужно передать исключение дальше по цепочке | |
259 chained.Reject(e); | |
260 } | |
261 }); | |
262 | |
263 return chained; | |
264 } | |
265 | |
266 public Promise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper) { | |
267 return Map(mapper, null); | |
268 } | |
269 | |
270 /// <summary> | |
271 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после | |
272 /// выполнения текущей, а результат текущей операции может быть использован для инициализации | |
273 /// новой операции. | |
274 /// </summary> | |
275 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam> | |
276 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param> | |
277 /// <param name="error">Обработчик ошибки. Данный обработчик получит | |
278 /// исключение возникшее при выполнении текуещй операции.</param> | |
279 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns> | |
280 public Promise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler error) { | |
281 | |
282 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно | |
283 // создать посредника, к которому будут подвызяваться следующие обработчики. | |
284 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы | |
285 // передать через него результаты работы. | |
286 var medium = new Promise<TNew>(this, true); | |
287 | |
288 AddHandler(new ResultHandlerInfo { | |
289 resultHandler = delegate(T result) { | |
290 if (medium.State == PromiseState.Cancelled) | |
291 return; | |
292 | |
293 var promise = chained(result); | |
294 | |
295 // notify chained operation that it's not needed | |
296 medium.Cancelled(() => promise.Cancel()); | |
297 promise.Then( | |
298 medium.Resolve, | |
299 medium.Reject | |
300 ); | |
301 }, | |
302 errorHandler = delegate(Exception e) { | |
303 if (error != null) | |
304 error(e); | |
305 // в случае ошибки нужно передать исключение дальше по цепочке | |
306 medium.Reject(e); | |
307 } | |
308 }); | |
309 | |
310 return medium; | |
311 } | |
312 | |
313 public Promise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained) { | |
314 return Chain(chained, null); | |
315 } | |
316 | |
317 public Promise<T> Cancelled(Action handler) { | |
318 if (handler == null) | |
319 return this; | |
320 lock (m_lock) { | |
321 if (m_state == PromiseState.Unresolved) | |
322 m_cancelHandlers.AddLast(handler); | |
323 else if (m_state == PromiseState.Cancelled) | |
324 handler(); | |
325 } | |
326 return this; | |
327 } | |
328 | |
329 public void HandleCancelled(Action handler) { | |
330 Cancelled(handler); | |
331 } | |
332 | |
333 /// <summary> | |
334 /// Дожидается отложенного обещания и в случае успеха, возвращает | |
335 /// его, результат, в противном случае бросает исключение. | |
336 /// </summary> | |
337 /// <remarks> | |
338 /// <para> | |
339 /// Если ожидание обещания было прервано по таймауту, это не значит, | |
340 /// что обещание было отменено или что-то в этом роде, это только | |
341 /// означает, что мы его не дождались, однако все зарегистрированные | |
342 /// обработчики, как были так остались и они будут вызваны, когда | |
343 /// обещание будет выполнено. | |
344 /// </para> | |
345 /// <para> | |
346 /// Такое поведение вполне оправдано поскольку таймаут может истечь | |
347 /// в тот момент, когда началась обработка цепочки обработчиков, и | |
348 /// к тому же текущее обещание может стоять в цепочке обещаний и его | |
349 /// отклонение может привести к непрогнозируемому результату. | |
350 /// </para> | |
351 /// </remarks> | |
352 /// <param name="timeout">Время ожидания</param> | |
353 /// <returns>Результат выполнения обещания</returns> | |
354 public T Join(int timeout) { | |
355 var evt = new ManualResetEvent(false); | |
356 Anyway(() => evt.Set()); | |
357 Cancelled(() => evt.Set()); | |
358 | |
359 if (!evt.WaitOne(timeout, true)) | |
360 throw new TimeoutException(); | |
361 | |
362 switch (State) { | |
363 case PromiseState.Resolved: | |
364 return m_result; | |
365 case PromiseState.Cancelled: | |
366 throw new OperationCanceledException(); | |
367 case PromiseState.Rejected: | |
368 throw new TargetInvocationException(m_error); | |
369 default: | |
370 throw new ApplicationException(String.Format("Invalid promise state {0}", State)); | |
371 } | |
372 } | |
373 | |
374 public T Join() { | |
375 return Join(Timeout.Infinite); | |
376 } | |
377 | |
378 void AddHandler(ResultHandlerInfo handler) { | |
379 bool invokeRequired = false; | |
380 | |
381 lock (m_lock) { | |
382 m_childrenCount++; | |
383 if (m_state == PromiseState.Unresolved) { | |
384 m_resultHandlers.AddLast(handler); | |
385 } else | |
386 invokeRequired = true; | |
387 } | |
388 | |
389 // обработчики не должны блокировать сам объект | |
390 if (invokeRequired) | |
391 InvokeHandler(handler); | |
392 } | |
393 | |
394 void InvokeHandler(ResultHandlerInfo handler) { | |
395 switch (m_state) { | |
396 case PromiseState.Resolved: | |
397 try { | |
398 if (handler.resultHandler != null) | |
399 handler.resultHandler(m_result); | |
400 } catch (Exception e) { | |
401 try { | |
402 if (handler.errorHandler != null) | |
403 handler.errorHandler(e); | |
404 } catch { } | |
405 } | |
406 break; | |
407 case PromiseState.Rejected: | |
408 try { | |
409 if (handler.errorHandler != null) | |
410 handler.errorHandler(m_error); | |
411 } catch { } | |
412 break; | |
413 default: | |
414 // do nothing | |
415 return; | |
416 } | |
417 } | |
418 | |
419 | 503 |
420 | 504 |
421 public bool IsExclusive { | 505 public bool IsExclusive { |
422 get { | 506 get { |
423 lock (m_lock) { | 507 lock (m_lock) { |
432 return m_state; | 516 return m_state; |
433 } | 517 } |
434 } | 518 } |
435 } | 519 } |
436 | 520 |
437 public bool Cancel(bool dependencies) { | 521 protected bool Cancel(bool dependencies) { |
438 bool result; | 522 bool result; |
439 | 523 |
440 lock (m_lock) { | 524 lock (m_lock) { |
441 if (m_state == PromiseState.Unresolved) { | 525 if (m_state == PromiseState.Unresolved) { |
442 m_state = PromiseState.Cancelled; | 526 m_state = PromiseState.Cancelled; |
448 | 532 |
449 if (result) | 533 if (result) |
450 OnStateChanged(); | 534 OnStateChanged(); |
451 | 535 |
452 if (dependencies && m_parent != null && m_parent.IsExclusive) { | 536 if (dependencies && m_parent != null && m_parent.IsExclusive) { |
453 m_parent.Cancel(true); | 537 m_parent.Cancel(); |
454 } | 538 } |
455 | 539 |
456 return result; | 540 return result; |
457 } | 541 } |
458 } | 542 } |