##// END OF EJS Templates
minor fixes
cin -
r105:4d308952fd5e v2
parent child
Show More
@@ -1,434 +1,449
1 1 using System;
2 2 using System.Reflection;
3 3 using System.Threading;
4 4 using Implab.Parallels;
5 5
6 6 #if MONO
7 7
8 8 using NUnit.Framework;
9 9 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
10 10 using TestMethod = NUnit.Framework.TestAttribute;
11 11
12 12 #else
13 13
14 14 using Microsoft.VisualStudio.TestTools.UnitTesting;
15 15
16 16 #endif
17 17
18 18 namespace Implab.Test {
19 19 [TestClass]
20 20 public class AsyncTests {
21 21 [TestMethod]
22 22 public void ResolveTest() {
23 23 int res = -1;
24 24 var p = new Promise<int>();
25 25 p.Then(x => res = x);
26 26 p.Resolve(100);
27 27
28 28 Assert.AreEqual(100, res);
29 29 }
30 30
31 31 [TestMethod]
32 32 public void RejectTest() {
33 33 int res = -1;
34 34 Exception err = null;
35 35
36 36 var p = new Promise<int>();
37 37 p.Then(
38 38 x => res = x,
39 39 e => {
40 40 err = e;
41 41 return -2;
42 42 }
43 43 );
44 44 p.Reject(new ApplicationException("error"));
45 45
46 46 Assert.AreEqual(res, -1);
47 47 Assert.AreEqual(err.Message, "error");
48 48
49 49 }
50 50
51 51 [TestMethod]
52 52 public void CancelExceptionTest() {
53 53 var p = new Promise<bool>();
54 54 p.Cancel();
55 55
56 56 var p2 = p.Cancelled(() => {
57 57 throw new ApplicationException("CANCELLED");
58 58 });
59 59
60 60 try {
61 61 p2.Join();
62 62 Assert.Fail();
63 63 } catch (ApplicationException err) {
64 64 Assert.AreEqual("CANCELLED", err.InnerException.Message);
65 65 }
66 66
67 67 }
68 68
69 69 [TestMethod]
70 70 public void ContinueOnCancelTest() {
71 71 var p = new Promise<bool>();
72 72 p.Cancel();
73 73
74 74 var p2 = p
75 75 .Cancelled(() => {
76 76 throw new ApplicationException("CANCELLED");
77 77 })
78 78 .Error(e => true);
79 79
80 80 Assert.AreEqual(true, p2.Join());
81 81 }
82 82
83 83 [TestMethod]
84 84 public void JoinSuccessTest() {
85 85 var p = new Promise<int>();
86 86 p.Resolve(100);
87 87 Assert.AreEqual(p.Join(), 100);
88 88 }
89 89
90 90 [TestMethod]
91 91 public void JoinFailTest() {
92 92 var p = new Promise<int>();
93 93 p.Reject(new ApplicationException("failed"));
94 94
95 95 try {
96 96 p.Join();
97 97 throw new ApplicationException("WRONG!");
98 98 } catch (TargetInvocationException err) {
99 99 Assert.AreEqual(err.InnerException.Message, "failed");
100 100 } catch {
101 101 Assert.Fail("Got wrong excaption");
102 102 }
103 103 }
104 104
105 105 [TestMethod]
106 106 public void MapTest() {
107 107 var p = new Promise<int>();
108 108
109 109 var p2 = p.Then(x => x.ToString());
110 110 p.Resolve(100);
111 111
112 112 Assert.AreEqual(p2.Join(), "100");
113 113 }
114 114
115 115 [TestMethod]
116 116 public void FixErrorTest() {
117 117 var p = new Promise<int>();
118 118
119 119 var p2 = p.Error(e => 101);
120 120
121 121 p.Reject(new Exception());
122 122
123 123 Assert.AreEqual(p2.Join(), 101);
124 124 }
125 125
126 126 [TestMethod]
127 127 public void ChainTest() {
128 128 var p1 = new Promise<int>();
129 129
130 130 var p3 = p1.Chain(x => {
131 131 var p2 = new Promise<string>();
132 132 p2.Resolve(x.ToString());
133 133 return p2;
134 134 });
135 135
136 136 p1.Resolve(100);
137 137
138 138 Assert.AreEqual(p3.Join(), "100");
139 139 }
140 140
141 141 [TestMethod]
142 public void ChainFailTest() {
143 var p1 = new Promise<int>();
144
145 var p3 = p1.Chain(x => {
146 var p2 = new Promise<string>();
147 p2.Reject(new Exception("DIE!!!"));
148 return p2;
149 });
150
151 p1.Resolve(100);
152
153 Assert.IsTrue(p3.IsResolved);
154 }
155
156 [TestMethod]
142 157 public void PoolTest() {
143 158 var pid = Thread.CurrentThread.ManagedThreadId;
144 159 var p = AsyncPool.Invoke(() => Thread.CurrentThread.ManagedThreadId);
145 160
146 161 Assert.AreNotEqual(pid, p.Join());
147 162 }
148 163
149 164 [TestMethod]
150 165 public void WorkerPoolSizeTest() {
151 166 var pool = new WorkerPool(5, 10, 1);
152 167
153 168 Assert.AreEqual(5, pool.PoolSize);
154 169
155 170 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
156 171 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
157 172 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
158 173
159 174 Assert.AreEqual(5, pool.PoolSize);
160 175
161 176 for (int i = 0; i < 100; i++)
162 177 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
163 178 Thread.Sleep(200);
164 179 Assert.AreEqual(10, pool.PoolSize);
165 180
166 181 pool.Dispose();
167 182 }
168 183
169 184 [TestMethod]
170 185 public void WorkerPoolCorrectTest() {
171 186 var pool = new WorkerPool(0,1000,100);
172 187
173 188 const int iterations = 1000;
174 189 int pending = iterations;
175 190 var stop = new ManualResetEvent(false);
176 191
177 192 var count = 0;
178 193 for (int i = 0; i < iterations; i++) {
179 194 pool
180 195 .Invoke(() => 1)
181 196 .Then(x => Interlocked.Add(ref count, x))
182 197 .Then(x => Math.Log10(x))
183 198 .Anyway(() => {
184 199 Interlocked.Decrement(ref pending);
185 200 if (pending == 0)
186 201 stop.Set();
187 202 });
188 203 }
189 204
190 205 stop.WaitOne();
191 206
192 207 Assert.AreEqual(iterations, count);
193 208 Console.WriteLine("Max threads: {0}", pool.MaxRunningThreads);
194 209 pool.Dispose();
195 210
196 211 }
197 212
198 213 [TestMethod]
199 214 public void WorkerPoolDisposeTest() {
200 215 var pool = new WorkerPool(5, 20);
201 216 Assert.AreEqual(5, pool.PoolSize);
202 217 pool.Dispose();
203 218 Thread.Sleep(500);
204 219 Assert.AreEqual(0, pool.PoolSize);
205 220 pool.Dispose();
206 221 }
207 222
208 223 [TestMethod]
209 224 public void MTQueueTest() {
210 225 var queue = new MTQueue<int>();
211 226 int res;
212 227
213 228 queue.Enqueue(10);
214 229 Assert.IsTrue(queue.TryDequeue(out res));
215 230 Assert.AreEqual(10, res);
216 231 Assert.IsFalse(queue.TryDequeue(out res));
217 232
218 233 for (int i = 0; i < 1000; i++)
219 234 queue.Enqueue(i);
220 235
221 236 for (int i = 0; i < 1000; i++) {
222 237 queue.TryDequeue(out res);
223 238 Assert.AreEqual(i, res);
224 239 }
225 240
226 241 int writers = 0;
227 242 int readers = 0;
228 243 var stop = new ManualResetEvent(false);
229 244 int total = 0;
230 245
231 246 const int itemsPerWriter = 10000;
232 247 const int writersCount = 10;
233 248
234 249 for (int i = 0; i < writersCount; i++) {
235 250 Interlocked.Increment(ref writers);
236 251 AsyncPool
237 252 .InvokeNewThread(() => {
238 253 for (int ii = 0; ii < itemsPerWriter; ii++) {
239 254 queue.Enqueue(1);
240 255 }
241 256 return 1;
242 257 })
243 258 .Anyway(() => Interlocked.Decrement(ref writers));
244 259 }
245 260
246 261 for (int i = 0; i < 10; i++) {
247 262 Interlocked.Increment(ref readers);
248 263 AsyncPool
249 264 .InvokeNewThread(() => {
250 265 int t;
251 266 do {
252 267 while (queue.TryDequeue(out t))
253 268 Interlocked.Add(ref total, t);
254 269 } while (writers > 0);
255 270 return 1;
256 271 })
257 272 .Anyway(() => {
258 273 Interlocked.Decrement(ref readers);
259 274 if (readers == 0)
260 275 stop.Set();
261 276 });
262 277 }
263 278
264 279 stop.WaitOne();
265 280
266 281 Assert.AreEqual(itemsPerWriter * writersCount, total);
267 282 }
268 283
269 284 [TestMethod]
270 285 public void ParallelMapTest() {
271 286
272 287 const int count = 100000;
273 288
274 289 var args = new double[count];
275 290 var rand = new Random();
276 291
277 292 for (int i = 0; i < count; i++)
278 293 args[i] = rand.NextDouble();
279 294
280 295 var t = Environment.TickCount;
281 296 var res = args.ParallelMap(x => Math.Sin(x*x), 4).Join();
282 297
283 298 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
284 299
285 300 t = Environment.TickCount;
286 301 for (int i = 0; i < count; i++)
287 302 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
288 303 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
289 304 }
290 305
291 306 [TestMethod]
292 307 public void ChainedMapTest() {
293 308
294 309 using (var pool = new WorkerPool(0,10,1)) {
295 310 const int count = 10000;
296 311
297 312 var args = new double[count];
298 313 var rand = new Random();
299 314
300 315 for (int i = 0; i < count; i++)
301 316 args[i] = rand.NextDouble();
302 317
303 318 var t = Environment.TickCount;
304 319 var res = args
305 320 .ChainedMap(
306 321 // Analysis disable once AccessToDisposedClosure
307 322 x => pool.Invoke(
308 323 () => Math.Sin(x * x)
309 324 ),
310 325 4
311 326 )
312 327 .Join();
313 328
314 329 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
315 330
316 331 t = Environment.TickCount;
317 332 for (int i = 0; i < count; i++)
318 333 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
319 334 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
320 335 Console.WriteLine("Max workers: {0}", pool.MaxRunningThreads);
321 336 }
322 337 }
323 338
324 339 [TestMethod]
325 340 public void ParallelForEachTest() {
326 341
327 342 const int count = 100000;
328 343
329 344 var args = new int[count];
330 345 var rand = new Random();
331 346
332 347 for (int i = 0; i < count; i++)
333 348 args[i] = (int)(rand.NextDouble() * 100);
334 349
335 350 int result = 0;
336 351
337 352 var t = Environment.TickCount;
338 353 args.ParallelForEach(x => Interlocked.Add(ref result, x), 4).Join();
339 354
340 355 Console.WriteLine("Iteration complete in {0} ms, result: {1}", Environment.TickCount - t, result);
341 356
342 357 int result2 = 0;
343 358
344 359 t = Environment.TickCount;
345 360 for (int i = 0; i < count; i++)
346 361 result2 += args[i];
347 362 Assert.AreEqual(result2, result);
348 363 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
349 364 }
350 365
351 366 [TestMethod]
352 367 public void ComplexCase1Test() {
353 368 var flags = new bool[3];
354 369
355 370 // op1 (aync 200ms) => op2 (async 200ms) => op3 (sync map)
356 371
357 372 var step1 = PromiseHelper
358 373 .Sleep(200, "Alan")
359 374 .Cancelled(() => flags[0] = true);
360 375 var p = step1
361 376 .Chain(x =>
362 377 PromiseHelper
363 378 .Sleep(200, "Hi, " + x)
364 379 .Then(y => y)
365 380 .Cancelled(() => flags[1] = true)
366 381 )
367 382 .Cancelled(() => flags[2] = true);
368 383 step1.Join();
369 384 p.Cancel();
370 385 try {
371 386 Assert.AreEqual(p.Join(), "Hi, Alan");
372 387 Assert.Fail("Shouldn't get here");
373 388 } catch (OperationCanceledException) {
374 389 }
375 390
376 391 Assert.IsFalse(flags[0]);
377 392 Assert.IsTrue(flags[1]);
378 393 Assert.IsTrue(flags[2]);
379 394 }
380 395
381 396 [TestMethod]
382 397 public void ChainedCancel1Test() {
383 398 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ сцСплСнной асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ всС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ
384 399 // Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ ошибкой OperationCanceledException
385 400 var p = PromiseHelper
386 401 .Sleep(1, "Hi, HAL!")
387 402 .Then(x => {
388 403 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
389 404 var result = PromiseHelper.Sleep(1000, "HEM ENABLED!!!");
390 405 // вторая опСрация отмСняСт ΠΏΠ΅Ρ€Π²ΡƒΡŽ Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ
391 406 PromiseHelper
392 407 .Sleep(100, "HAL, STOP!")
393 408 .Then(result.Cancel);
394 409 return result;
395 410 });
396 411 try {
397 412 p.Join();
398 413 } catch (TargetInvocationException err) {
399 414 Assert.IsTrue(err.InnerException is OperationCanceledException);
400 415 }
401 416 }
402 417
403 418 [TestMethod]
404 419 public void ChainedCancel2Test() {
405 420 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΡ‚ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ
406 421 var pSurvive = new Promise<bool>();
407 422 var hemStarted = new ManualResetEvent(false);
408 423 var p = PromiseHelper
409 424 .Sleep(1, "Hi, HAL!")
410 425 .Chain(x => {
411 426 hemStarted.Set();
412 427 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
413 428 var result = PromiseHelper
414 429 .Sleep(10000, "HEM ENABLED!!!")
415 430 .Then(s => pSurvive.Resolve(false));
416 431
417 432 result
418 433 .Cancelled(() => pSurvive.Resolve(true));
419 434
420 435 return result;
421 436 });
422 437
423 438 hemStarted.WaitOne();
424 439 p.Cancel();
425 440
426 441 try {
427 442 p.Join();
428 443 } catch (OperationCanceledException) {
429 444 Assert.IsTrue(pSurvive.Join());
430 445 }
431 446 }
432 447 }
433 448 }
434 449
@@ -1,932 +1,932
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Reflection;
4 4 using System.Threading;
5 5 using Implab.Parallels;
6 6
7 7 namespace Implab {
8 8
9 9 /// <summary>
10 10 /// Класс для асинхронного получСния Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ². Π’Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ΅ "ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅".
11 11 /// </summary>
12 12 /// <typeparam name="T">Π’ΠΈΠΏ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°</typeparam>
13 13 /// <remarks>
14 14 /// <para>БСрвис ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ Π΄Π°Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°ΠΈΠ½ΠΈΠ΅ ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ,
15 15 /// ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ² Ρ‚Π°ΠΊΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ряд ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Ρ… Π²Ρ‹Π·ΠΎΠ²ΠΎ для получСния
16 16 /// событий выполнСния обСщания, Ρ‚ΠΎΠ΅ΡΡ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈ прСдоставлСнии Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².</para>
17 17 /// <para>
18 18 /// ΠžΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚Π°ΠΊ ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ с ошибкой. Для подписки Π½Π°
19 19 /// Π΄Π°Π½Π½Ρ‹Π΅ события ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Then</c>.
20 20 /// </para>
21 21 /// <para>
22 22 /// БСрвис, Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ (Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ с ошибкой),
23 23 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Resolve</c> Π»ΠΈΠ±ΠΎ <c>Reject</c> для оповСщСния ΠΊΠ»ΠΈΠ΅Ρ‚Π½Π° ΠΎ
24 24 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ обСщания.
25 25 /// </para>
26 26 /// <para>
27 27 /// Если сСрвСр успСл Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΅Ρ‰Π΅ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π° Π½Π΅Π³ΠΎ подписался,
28 28 /// Ρ‚ΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ подписки ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰ΠΈΠ΅ события Π² синхронном
29 29 /// Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ Π² любом случаС. Π˜Π½Π°Ρ‡Π΅, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π²
30 30 /// список Π² порядкС подписания ΠΈ Π² этом ΠΆΠ΅ порядкС ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ
31 31 /// обСщания.
32 32 /// </para>
33 33 /// <para>
34 34 /// ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ обСщания ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π»ΠΈΠ±ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ
35 35 /// связанныС асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚ обСщания. Для этого слСдуСт
36 36 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ Ρ„ΠΎΡ€ΠΌΡƒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ <c>Then</c>.
37 37 /// </para>
38 38 /// <para>
39 39 /// Π’Π°ΠΊΠΆΠ΅ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ <c>Resolve</c> ΠΈ <c>Reject</c> Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ
40 40 /// Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Ρ‚ΠΎΡ€ обСщания ΠΈΠ½Π°Ρ‡Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ противорСчия.
41 41 /// </para>
42 42 /// </remarks>
43 43 public class Promise<T> : IPromise<T> {
44 44
45 45 protected struct HandlerDescriptor {
46 46 public Action<T> resultHandler;
47 47 public Func<Exception,T> errorHandler;
48 48 public Action cancellHandler;
49 49 public Promise<T> medium;
50 50
51 51 public void Resolve(T result) {
52 52 if (resultHandler != null) {
53 53 try {
54 54 resultHandler(result);
55 55 } catch (Exception e) {
56 56 Reject(e);
57 57 return;
58 58 }
59 59 }
60 60 if (medium != null)
61 61 medium.Resolve(result);
62 62 }
63 63
64 64 public void Reject(Exception err) {
65 65 if (errorHandler != null) {
66 66 try {
67 67 var res = errorHandler(err);
68 68 if (medium != null)
69 69 medium.Resolve(res);
70 70 /*} catch (TransientPromiseException err2) {
71 71 if (medium != null)
72 72 medium.Reject(err2.InnerException);*/
73 73 } catch (Exception err2) {
74 74 if (medium != null)
75 75 medium.Reject(err2);
76 76 }
77 77 } else if (medium != null)
78 78 medium.Reject(err);
79 79 }
80 80
81 81 public void Cancel() {
82 82 if (cancellHandler != null) {
83 83 try {
84 84 cancellHandler();
85 85 } catch (Exception err) {
86 86 Reject(err);
87 87 return;
88 88 }
89 89 }
90 90 if (medium != null)
91 91 medium.Cancel();
92 92 }
93 93 }
94 94
95 95 const int UNRESOLVED_SATE = 0;
96 96 const int TRANSITIONAL_STATE = 1;
97 97 const int SUCCEEDED_STATE = 2;
98 98 const int REJECTED_STATE = 3;
99 99 const int CANCELLED_STATE = 4;
100 100
101 101 int m_childrenCount;
102 102 int m_state;
103 103 T m_result;
104 104 Exception m_error;
105 105
106 106 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
107 107
108 108 public Promise() {
109 109 }
110 110
111 111 public Promise(IPromise parent) {
112 112 if (parent != null)
113 113 AddHandler(
114 114 null,
115 115 null,
116 116 () => {
117 117 if (parent.IsExclusive)
118 118 parent.Cancel();
119 119 },
120 120 null,
121 121 false
122 122 );
123 123 }
124 124
125 125 bool BeginTransit() {
126 126 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
127 127 }
128 128
129 129 void CompleteTransit(int state) {
130 130 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
131 131 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
132 132 }
133 133
134 134 void WaitTransition() {
135 135 while (m_state == TRANSITIONAL_STATE) {
136 136 Thread.MemoryBarrier();
137 137 }
138 138 }
139 139
140 140 public bool IsResolved {
141 141 get {
142 142 Thread.MemoryBarrier();
143 143 return m_state > 1;
144 144 }
145 145 }
146 146
147 147 public bool IsCancelled {
148 148 get {
149 149 Thread.MemoryBarrier();
150 150 return m_state == CANCELLED_STATE;
151 151 }
152 152 }
153 153
154 154 public Type PromiseType {
155 155 get { return typeof(T); }
156 156 }
157 157
158 158 /// <summary>
159 159 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ.
160 160 /// </summary>
161 161 /// <param name="result">Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния.</param>
162 162 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
163 163 public void Resolve(T result) {
164 164 if (BeginTransit()) {
165 165 m_result = result;
166 166 CompleteTransit(SUCCEEDED_STATE);
167 167 OnStateChanged();
168 168 } else {
169 169 WaitTransition();
170 170 if (m_state != CANCELLED_STATE)
171 171 throw new InvalidOperationException("The promise is already resolved");
172 172 }
173 173 }
174 174
175 175 /// <summary>
176 176 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ выполнСния Π±ΡƒΠ΄Π΅Ρ‚ пустоС значСния.
177 177 /// </summary>
178 178 /// <remarks>
179 179 /// Π”Π°Π½Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΡƒΠ΄ΠΎΠ±Π΅Π½ Π² случаях, ΠΊΠΎΠ³Π΄Π° интСрСсСн Ρ„Π°ΠΊΡ‚ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π΅ΠΆΠ΅Π»ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
180 180 /// </remarks>
181 181 public void Resolve() {
182 182 Resolve(default(T));
183 183 }
184 184
185 185 /// <summary>
186 186 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
187 187 /// </summary>
188 188 /// <remarks>
189 189 /// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ‚ΠΎΡ‡Π½ΠΎΠΉ срСдС, ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ сразу нСсколько ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
190 190 /// ΠΌΠΎΠ³Ρƒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΡ€ΠΈ этом Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Π±ΡƒΠ΄Π΅Ρ‚ использована Π² качСствС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
191 191 /// Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹.
192 192 /// </remarks>
193 193 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
194 194 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
195 195 public void Reject(Exception error) {
196 196 if (BeginTransit()) {
197 197 m_error = error is TransientPromiseException ? error.InnerException : error;
198 198 CompleteTransit(REJECTED_STATE);
199 199 OnStateChanged();
200 200 } else {
201 201 WaitTransition();
202 202 if (m_state == SUCCEEDED_STATE)
203 203 throw new InvalidOperationException("The promise is already resolved");
204 204 }
205 205 }
206 206
207 207 /// <summary>
208 208 /// ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ, Ссли это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.
209 209 /// </summary>
210 210 /// <remarks>Для опрСдСлСния Π±Ρ‹Π»Π° Π»ΠΈ опСрация ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свойство <see cref="IsCancelled"/>.</remarks>
211 211 public void Cancel() {
212 212 if (BeginTransit()) {
213 213 CompleteTransit(CANCELLED_STATE);
214 214 OnStateChanged();
215 215 }
216 216 }
217 217
218 218 public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) {
219 219 if (success == null && error == null && cancel == null)
220 220 return this;
221 221
222 222 var medium = new Promise<T>(this);
223 223
224 224 AddHandler(success, error, cancel, medium, true);
225 225
226 226 return medium;
227 227 }
228 228
229 229 /// <summary>
230 230 /// Adds new handlers to this promise.
231 231 /// </summary>
232 232 /// <param name="success">The handler of the successfully completed operation.
233 233 /// This handler will recieve an operation result as a parameter.</param>
234 234 /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param>
235 235 /// <returns>The new promise chained to this one.</returns>
236 236 public IPromise<T> Then(Action<T> success, Func<Exception,T> error) {
237 237 if (success == null && error == null)
238 238 return this;
239 239
240 240 var medium = new Promise<T>(this);
241 241
242 242 AddHandler(success, error, null, medium, true);
243 243
244 244 return medium;
245 245 }
246 246
247 247
248 248
249 249
250 250 public IPromise<T> Then(Action<T> success) {
251 251 if (success == null)
252 252 return this;
253 253
254 254 var medium = new Promise<T>(this);
255 255
256 256 AddHandler(success, null, null, medium, true);
257 257
258 258 return medium;
259 259 }
260 260
261 261 /// <summary>
262 262 /// ПослСдний ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
263 263 /// </summary>
264 264 /// <param name="success"></param>
265 265 /// <param name="error"></param>
266 266 /// <param name="cancel"></param>
267 267 /// <remarks>
268 268 /// <para>
269 269 /// Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π½Π΅ создаСт связанного с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ обСщания ΠΈ ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½ для окончания
270 270 /// фсинхронной Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ.
271 271 /// </para>
272 272 /// <para>
273 273 /// Если Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ нСсколько Ρ€Π°Π·, Π»ΠΈΠ±ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, Ρ‚ΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ°
274 274 /// Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½ΠΎΠΉ <see cref="IsExclusive"/> ΠΈ, ΠΊΠ°ΠΊ слСдствиС, Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π° ΠΎΡ‚ΠΌΠ΅Π½Π°
275 275 /// всСй Ρ†Π΅ΠΏΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ снизу (с самого послСднСго обСщания).
276 276 /// </para>
277 277 /// </remarks>
278 278 public void On(Action<T> success, Action<Exception> error, Action cancel) {
279 279 if (success == null && error == null && cancel == null)
280 280 return;
281 281
282 282 Func<Exception,T> errorHandler = null;
283 283 if (error != null)
284 284 errorHandler = err => {
285 285 error(err);
286 286 return default(T);
287 287 };
288 288 AddHandler(success, errorHandler, cancel, null, false);
289 289 }
290 290
291 291 public void On(Action<T> success, Action<Exception> error) {
292 292 On(success, error, null);
293 293 }
294 294
295 295 public void On(Action<T> success) {
296 296 On(success, null, null);
297 297 }
298 298
299 299 public void On(Action handler, PromiseEventType events) {
300 300 Safe.ArgumentNotNull(handler, "handler");
301 301
302 302 Action<T> success = events.HasFlag(PromiseEventType.Success) ? new Action<T>(x => handler()) : null;
303 303 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => {
304 304 handler();
305 305 return default(T);
306 306 }) : null;
307 307 Action cancel = events.HasFlag(PromiseEventType.Cancelled) ? handler : null;
308 308
309 309 AddHandler(success, error, cancel, null, false);
310 310 }
311 311
312 312 public IPromise Error(Action<Exception> error) {
313 313 if (error == null)
314 314 return this;
315 315
316 316 var medium = new Promise<T>(this);
317 317
318 318 AddHandler(
319 319 null,
320 320 e => {
321 321 error(e);
322 322 return default(T);
323 323 },
324 324 null,
325 325 medium,
326 326 true
327 327 );
328 328
329 329 return medium;
330 330 }
331 331
332 332 /// <summary>
333 333 /// Handles error and allows to keep the promise.
334 334 /// </summary>
335 335 /// <remarks>
336 336 /// If the specified handler throws an exception, this exception will be used to reject the promise.
337 337 /// </remarks>
338 338 /// <param name="handler">The error handler which returns the result of the promise.</param>
339 339 /// <returns>New promise.</returns>
340 340 public IPromise<T> Error(Func<Exception,T> handler) {
341 341 if (handler == null)
342 342 return this;
343 343
344 344 var medium = new Promise<T>(this);
345 345
346 346 AddHandler(null, handler, null, medium, true);
347 347
348 348 return medium;
349 349 }
350 350
351 351 /// <summary>
352 352 /// ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.
353 353 /// </summary>
354 354 /// <typeparam name="TNew">Новый Ρ‚ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°.</typeparam>
355 355 /// <param name="mapper">ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.</param>
356 356 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
357 357 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
358 358 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ исходного обСщания.</returns>
359 359 /// <param name = "cancel"></param>
360 360 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error, Action cancel) {
361 361 Safe.ArgumentNotNull(mapper, "mapper");
362 362
363 363 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
364 364 var medium = new Promise<TNew>(this);
365 365
366 366 Action<T> resultHandler = result => medium.Resolve(mapper(result));
367 367 Func<Exception,T> errorHandler;
368 368 if (error != null)
369 369 errorHandler = e => {
370 370 try {
371 371 medium.Resolve(error(e));
372 372 } catch (Exception e2) {
373 373 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
374 374 medium.Reject(e2);
375 375 }
376 376 return default(T);
377 377 };
378 378 else
379 379 errorHandler = e => {
380 380 medium.Reject(e);
381 381 return default(T);
382 382 };
383 383
384 384 Action cancelHandler;
385 385 if (cancel != null)
386 386 cancelHandler = () => {
387 387 cancel();
388 388 medium.Cancel();
389 389 };
390 390 else
391 391 cancelHandler = medium.Cancel;
392 392
393 393
394 394 AddHandler(
395 395 resultHandler,
396 396 errorHandler,
397 397 cancelHandler,
398 398 null,
399 399 true
400 400 );
401 401
402 402 return medium;
403 403 }
404 404
405 405 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error) {
406 406 return Then(mapper, error, null);
407 407 }
408 408
409 409 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper) {
410 410 return Then(mapper, null, null);
411 411 }
412 412
413 413 /// <summary>
414 414 /// БцСпляСт нСсколько аснхронных ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Указанная асинхронная опСрация Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½Π° послС
415 415 /// выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ, Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ использован для ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ
416 416 /// Π½ΠΎΠ²ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.
417 417 /// </summary>
418 418 /// <typeparam name="TNew">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</typeparam>
419 419 /// <param name="chained">Асинхронная опСрация, которая Π΄ΠΎΠ»ΠΆΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°Ρ‡Π°Ρ‚ΡŒΡΡ послС выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ.</param>
420 420 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
421 421 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ Ρ‚Π΅ΠΊΡƒΠ΅Ρ‰ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
422 422 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ аснхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</returns>
423 423 /// <param name = "cancel"></param>
424 424 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error, Action cancel) {
425 425
426 426 Safe.ArgumentNotNull(chained, "chained");
427 427
428 428 // ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ связывания Π΅Ρ‰Π΅ Π½Π΅ Π½Π°Ρ‡Π°Ρ‚Π° асинхронная опСрация, поэтому Π½ΡƒΠΆΠ½ΠΎ
429 429 // ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ посрСдника, ΠΊ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠ΄Π²Ρ‹Π·ΡΠ²Π°Ρ‚ΡŒΡΡ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ.
430 430 // ΠΊΠΎΠ³Π΄Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Π°Ρ асинхронная опСрация, ΠΎΠ½Π° ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ ΠΊ посрСднику, Ρ‡Ρ‚ΠΎΠ±Ρ‹
431 431 // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹.
432 432 var medium = new Promise<TNew>(this);
433 433
434 434 Action<T> resultHandler = delegate(T result) {
435 435 if (medium.IsCancelled)
436 436 return;
437 437
438 438 var promise = chained(result);
439 439
440 440 promise.On(
441 441 medium.Resolve,
442 442 medium.Reject,
443 443 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
444 444 );
445 445
446 446 // notify chained operation that it's not needed anymore
447 447 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
448 448 // зависит IsExclusive
449 449 medium.On(
450 450 null,
451 451 null,
452 452 () => {
453 453 if (promise.IsExclusive)
454 454 promise.Cancel();
455 455 }
456 456 );
457 457 };
458 458
459 459 Func<Exception,T> errorHandler;
460 460
461 461 if (error != null)
462 462 errorHandler = delegate(Exception e) {
463 463 try {
464 464 var promise = error(e);
465 465
466 466 promise.On(
467 467 medium.Resolve,
468 468 medium.Reject,
469 469 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
470 470 );
471 471
472 472 // notify chained operation that it's not needed anymore
473 473 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
474 474 // зависит IsExclusive
475 475 medium.Cancelled(() => {
476 476 if (promise.IsExclusive)
477 477 promise.Cancel();
478 478 });
479 479 } catch (Exception e2) {
480 480 medium.Reject(e2);
481 481 }
482 482 return default(T);
483 483 };
484 484 else
485 485 errorHandler = err => {
486 486 medium.Reject(err);
487 487 return default(T);
488 488 };
489 489
490 490
491 491 Action cancelHandler;
492 492 if (cancel != null)
493 493 cancelHandler = () => {
494 494 if (cancel != null)
495 495 cancel();
496 496 medium.Cancel();
497 497 };
498 498 else
499 499 cancelHandler = medium.Cancel;
500 500
501 501 AddHandler(
502 502 resultHandler,
503 503 errorHandler,
504 504 cancelHandler,
505 505 null,
506 506 true
507 507 );
508 508
509 509 return medium;
510 510 }
511 511
512 512 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error) {
513 513 return Chain(chained, error, null);
514 514 }
515 515
516 516 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained) {
517 517 return Chain(chained, null, null);
518 518 }
519 519
520 520 public IPromise<T> Cancelled(Action handler) {
521 521 var medium = new Promise<T>(this);
522 522 AddHandler(null, null, handler, medium, false);
523 523 return medium;
524 524 }
525 525
526 526 /// <summary>
527 527 /// Adds the specified handler for all cases (success, error, cancel)
528 528 /// </summary>
529 529 /// <param name="handler">The handler that will be called anyway</param>
530 530 /// <returns>self</returns>
531 531 public IPromise<T> Anyway(Action handler) {
532 532 Safe.ArgumentNotNull(handler, "handler");
533 533
534 534 var medium = new Promise<T>(this);
535 535
536 536 AddHandler(
537 537 x => handler(),
538 538 e => {
539 539 handler();
540 540 throw new TransientPromiseException(e);
541 541 },
542 542 handler,
543 543 medium,
544 544 true
545 545 );
546 546
547 547 return medium;
548 548 }
549 549
550 550 /// <summary>
551 551 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ обСщания ΠΊ Π½ΡƒΠΆΠ½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ
552 552 /// </summary>
553 553 /// <typeparam name="T2"></typeparam>
554 554 /// <returns></returns>
555 555 public IPromise<T2> Cast<T2>() {
556 556 return Then(x => (T2)(object)x, null);
557 557 }
558 558
559 559 /// <summary>
560 560 /// ДоТидаСтся ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ обСщания ΠΈ Π² случаС успСха, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚
561 561 /// Π΅Π³ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС бросаСт ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.
562 562 /// </summary>
563 563 /// <remarks>
564 564 /// <para>
565 565 /// Если ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ обСщания Π±Ρ‹Π»ΠΎ ΠΏΡ€Π΅Ρ€Π²Π°Π½ΠΎ ΠΏΠΎ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρƒ, это Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚,
566 566 /// Ρ‡Ρ‚ΠΎ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ ΠΈΠ»ΠΈ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π² этом Ρ€ΠΎΠ΄Π΅, это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ
567 567 /// ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π΅Π³ΠΎ Π½Π΅ доТдались, ΠΎΠ΄Π½Π°ΠΊΠΎ всС зарСгистрированныС
568 568 /// ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, ΠΊΠ°ΠΊ Π±Ρ‹Π»ΠΈ Ρ‚Π°ΠΊ ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ ΠΈ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹, ΠΊΠΎΠ³Π΄Π°
569 569 /// ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
570 570 /// </para>
571 571 /// <para>
572 572 /// Π’Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π²ΠΏΠΎΠ»Π½Π΅ ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ΠΎ ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΡ‚Π΅Ρ‡ΡŒ
573 573 /// Π² Ρ‚ΠΎΡ‚ ΠΌΠΎΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠ³Π΄Π° Π½Π°Ρ‡Π°Π»Π°ΡΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ², ΠΈ
574 574 /// ΠΊ Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡ‚ΠΎΡΡ‚ΡŒ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ ΠΈ Π΅Π³ΠΎ
575 575 /// ΠΎΡ‚ΠΊΠ»ΠΎΠ½Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ Π½Π΅ΠΏΡ€ΠΎΠ³Π½ΠΎΠ·ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΌΡƒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρƒ.
576 576 /// </para>
577 577 /// </remarks>
578 578 /// <param name="timeout">ВрСмя оТидания</param>
579 579 /// <returns>Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния обСщания</returns>
580 580 public T Join(int timeout) {
581 581 var evt = new ManualResetEvent(false);
582 582 Anyway(() => evt.Set());
583 583
584 584 if (!evt.WaitOne(timeout, true))
585 585 throw new TimeoutException();
586 586
587 587 switch (m_state) {
588 588 case SUCCEEDED_STATE:
589 589 return m_result;
590 590 case CANCELLED_STATE:
591 591 throw new OperationCanceledException();
592 592 case REJECTED_STATE:
593 593 throw new TargetInvocationException(m_error);
594 594 default:
595 595 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
596 596 }
597 597 }
598 598
599 599 public T Join() {
600 600 return Join(Timeout.Infinite);
601 601 }
602 602
603 603 void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium, bool inc) {
604 604 if (inc)
605 605 Interlocked.Increment(ref m_childrenCount);
606 606
607 607 var handler = new HandlerDescriptor {
608 608 resultHandler = success,
609 609 errorHandler = error,
610 610 cancellHandler = cancel,
611 611 medium = medium
612 612 };
613 613
614 614 bool queued;
615 615
616 616 if (!IsResolved) {
617 617 m_handlers.Enqueue(handler);
618 618 queued = true;
619 619 } else {
620 620 // the promise is in resolved state, just invoke the handled with minimum overhead
621 621 queued = false;
622 622 InvokeHandler(handler);
623 623 }
624 624
625 625 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
626 626 // if the promise have been resolved while we was adding handler to the queue
627 627 // we can't guarantee that someone is still processing it
628 628 // therefore we will fetch a handler from the queue and execute it
629 629 // note that fetched handler may be not the one that we have added
630 630 // even we can fetch no handlers at all :)
631 631 InvokeHandler(handler);
632 632 }
633 633
634 634 protected virtual void InvokeHandler(HandlerDescriptor handler) {
635 635 switch (m_state) {
636 636 case SUCCEEDED_STATE:
637 637 handler.Resolve(m_result);
638 638 break;
639 639 case REJECTED_STATE:
640 640 handler.Reject(m_error);
641 641 break;
642 642 case CANCELLED_STATE:
643 643 handler.Cancel();
644 644 break;
645 645 default:
646 646 // do nothing
647 647 return;
648 648 }
649 649 }
650 650
651 651 void OnStateChanged() {
652 652 HandlerDescriptor handler;
653 653 while (m_handlers.TryDequeue(out handler))
654 654 InvokeHandler(handler);
655 655 }
656 656
657 657 public bool IsExclusive {
658 658 get {
659 659 return m_childrenCount <= 1;
660 660 }
661 661 }
662 662
663 663 /// <summary>
664 664 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ являСтся массив Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
665 665 /// Если хотябы ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
666 666 /// ΠŸΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ обСщания, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ обСщания Ρ‚Π°ΠΊΠΆΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Ρ‹, Ссли Π½ΠΈΠΊΡ‚ΠΎ большС Π½Π° Π½ΠΈΡ… Π½Π΅ подписан.
667 667 /// </summary>
668 668 /// <param name="promises">Бписок ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. Если список пустой, Ρ‚ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ возвращаСтся ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌ.</param>
669 669 /// <returns>ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.</returns>
670 670 /// <exception cref="ArgumentNullException"><paramref name="promises"/> Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ null</exception>
671 671 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) {
672 672 if (promises == null)
673 673 throw new ArgumentNullException();
674 674
675 675 // создаСм аккумулятор для Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² ΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
676 676 var result = new T[promises.Count];
677 677 var promise = new Promise<T[]>();
678 678
679 679 // special case
680 680 if (promises.Count == 0) {
681 681 promise.Resolve(result);
682 682 return promise;
683 683 }
684 684
685 685 int pending = promises.Count;
686 686
687 687 for (int i = 0; i < promises.Count; i++) {
688 688 var dest = i;
689 689
690 690 if (promises[i] != null) {
691 691 promises[i].Then(
692 692 x => {
693 693 result[dest] = x;
694 694 if (Interlocked.Decrement(ref pending) == 0)
695 695 promise.Resolve(result);
696 696 },
697 697 e => {
698 698 promise.Reject(e);
699 699 return default(T);
700 700 }
701 701 );
702 702 } else {
703 703 if (Interlocked.Decrement(ref pending) == 0)
704 704 promise.Resolve(result);
705 705 }
706 706 }
707 707
708 708 promise.Cancelled(
709 709 () => {
710 710 foreach (var d in promises)
711 711 if (d != null && d.IsExclusive)
712 712 d.Cancel();
713 713 }
714 714 );
715 715
716 716 return promise;
717 717 }
718 718
719 719 /// <summary>
720 720 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ
721 721 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ всСх ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. ΠŸΡ€ΠΈ этом Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ
722 722 /// ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ.
723 723 /// </summary>
724 724 /// <param name="promises">ΠšΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±ΡŠΠ΅Π΄Π΅Π½Π΅Π½Ρ‹ Π² ΠΎΠ΄Π½ΠΎ.</param>
725 725 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅.</returns>
726 726 /// <remarks>
727 727 /// Если Π² ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡŒΡΡ <c>null</c>, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ΡΡ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ обСщания.
728 728 /// </remarks>
729 729 public static IPromise CreateComposite(ICollection<IPromise> promises) {
730 730 if (promises == null)
731 731 throw new ArgumentNullException();
732 732 if (promises.Count == 0)
733 733 return Promise<object>.ResultToPromise(null);
734 734
735 735 int countdown = promises.Count;
736 736
737 737 var result = new Promise<object>();
738 738
739 739 foreach (var d in promises) {
740 740 if (d == null) {
741 741 if (Interlocked.Decrement(ref countdown) == 0)
742 742 result.Resolve(null);
743 743 } else {
744 744 d.Then(() => {
745 745 if (Interlocked.Decrement(ref countdown) == 0)
746 746 result.Resolve(null);
747 747 });
748 748 }
749 749 }
750 750
751 751 result.Cancelled(() => {
752 752 foreach (var d in promises)
753 753 if (d != null && d.IsExclusive)
754 754 d.Cancel();
755 755 });
756 756
757 757 return result;
758 758 }
759 759
760 760 public static Promise<T> ResultToPromise(T result) {
761 761 var p = new Promise<T>();
762 762 p.Resolve(result);
763 763 return p;
764 764 }
765 765
766 766 public static Promise<T> ExceptionToPromise(Exception error) {
767 767 if (error == null)
768 768 throw new ArgumentNullException();
769 769
770 770 var p = new Promise<T>();
771 771 p.Reject(error);
772 772 return p;
773 773 }
774 774
775 775 #region IPromiseBase explicit implementation
776 776
777 777 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
778 778 return Then(
779 779 success != null ? new Action<T>(x => success()) : null,
780 780 error != null ? new Func<Exception,T>(e => {
781 781 error(e);
782 782 return default(T);
783 783 }) : null,
784 784 cancel
785 785 );
786 786 }
787 787
788 788 IPromise IPromise.Then(Action success, Action<Exception> error) {
789 789 return Then(
790 790 success != null ? new Action<T>(x => success()) : null,
791 791 error != null ? new Func<Exception,T>(e => {
792 792 error(e);
793 793 return default(T);
794 794 }) : null
795 795 );
796 796 }
797 797
798 798 IPromise IPromise.Then(Action success) {
799 799 Safe.ArgumentNotNull(success, "success");
800 800 return Then(x => success());
801 801 }
802 802
803 803 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
804 804 return ChainNoResult(chained, error, cancel);
805 805 }
806 806
807 807 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
808 808 Safe.ArgumentNotNull(chained, "chained");
809 809
810 810 var medium = new Promise<object>(this);
811 811
812 812 Action<T> resultHandler = delegate {
813 813 if (medium.IsCancelled)
814 814 return;
815 815
816 816 var promise = chained();
817 817
818 818 promise.On(
819 819 medium.Resolve,
820 820 medium.Reject,
821 821 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
822 822 );
823 823
824 824 // notify chained operation that it's not needed anymore
825 825 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
826 826 // зависит IsExclusive
827 827 medium.Cancelled(() => {
828 828 if (promise.IsExclusive)
829 829 promise.Cancel();
830 830 });
831 831 };
832 832
833 833 Func<Exception,T> errorHandler;
834 834
835 835 if (error != null)
836 836 errorHandler = delegate(Exception e) {
837 837 try {
838 838 var promise = error(e);
839 839
840 840 promise.On(
841 841 medium.Resolve,
842 842 medium.Reject,
843 843 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
844 844 );
845 845
846 846 // notify chained operation that it's not needed anymore
847 847 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
848 848 // зависит IsExclusive
849 849 medium.Cancelled(() => {
850 850 if (promise.IsExclusive)
851 851 promise.Cancel();
852 852 });
853 853 } catch (Exception e2) {
854 854 medium.Reject(e2);
855 855 }
856 856 return default(T);
857 857 };
858 858 else
859 859 errorHandler = err => {
860 860 medium.Reject(err);
861 861 return default(T);
862 862 };
863 863
864 864
865 865 Action cancelHandler;
866 866 if (cancel != null)
867 867 cancelHandler = () => {
868 868 if (cancel != null)
869 869 cancel();
870 870 medium.Cancel();
871 871 };
872 872 else
873 873 cancelHandler = medium.Cancel;
874 874
875 875 AddHandler(
876 876 resultHandler,
877 877 errorHandler,
878 878 cancelHandler,
879 879 null,
880 880 true
881 881 );
882 882
883 883 return medium;
884 884 }
885 885
886 886 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error) {
887 887 return ChainNoResult(chained, error, null);
888 888 }
889 889
890 890 IPromise IPromise.Chain(Func<IPromise> chained) {
891 891 return ChainNoResult(chained, null, null);
892 892 }
893 893
894 894
895 895 void IPromise.On(Action success, Action<Exception> error, Action cancel) {
896 On(x => success(), error, cancel);
896 On(success != null ? new Action<T>(x => success()) : null, error, cancel);
897 897 }
898 898
899 899 void IPromise.On(Action success, Action<Exception> error) {
900 900 On(x => success(), error, null);
901 901 }
902 902
903 903 void IPromise.On(Action success) {
904 904 On(x => success(), null, null);
905 905 }
906 906
907 907 IPromise IPromise.Error(Action<Exception> error) {
908 908 return Error(error);
909 909 }
910 910
911 911 IPromise IPromise.Anyway(Action handler) {
912 912 return Anyway(handler);
913 913 }
914 914
915 915 IPromise IPromise.Cancelled(Action handler) {
916 916 return Cancelled(handler);
917 917 }
918 918
919 919 void IPromise.Join() {
920 920 Join();
921 921 }
922 922
923 923 void IPromise.Join(int timeout) {
924 924 Join(timeout);
925 925 }
926 926
927 927 #endregion
928 928
929 929
930 930
931 931 }
932 932 }
General Comments 0
You need to be logged in to leave comments. Login now