1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
2 
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Diagnostics.CodeAnalysis;
8 using System.Globalization;
9 using System.Linq;
10 using System.Reflection;
11 using System.Threading;
12 using System.Threading.Tasks;
13 using Microsoft.AspNet.SignalR.Infrastructure;
14 
15 namespace Microsoft.AspNet.SignalR
16 {
17     internal static class TaskAsyncHelper
18     {
19         private static readonly Task _emptyTask = MakeTask<object>(null);
20         private static readonly Task<bool> _trueTask = MakeTask<bool>(true);
21         private static readonly Task<bool> _falseTask = MakeTask<bool>(false);
22 
MakeTask(T value)23         private static Task<T> MakeTask<T>(T value)
24         {
25             return FromResult<T>(value);
26         }
27 
28         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
29         public static Task Empty
30         {
31             get
32             {
33                 return _emptyTask;
34             }
35         }
36 
37         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
38         public static Task<bool> True
39         {
40             get
41             {
42                 return _trueTask;
43             }
44         }
45 
46         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
47         public static Task<bool> False
48         {
49             get
50             {
51                 return _falseTask;
52             }
53         }
54 
55         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
OrEmpty(this Task task)56         public static Task OrEmpty(this Task task)
57         {
58             return task ?? Empty;
59         }
60 
61         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
OrEmpty(this Task<T> task)62         public static Task<T> OrEmpty<T>(this Task<T> task)
63         {
64             return task ?? TaskCache<T>.Empty;
65         }
66 
67         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
68         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod, object state)69         public static Task FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod, object state)
70         {
71             try
72             {
73                 return Task.Factory.FromAsync(beginMethod, endMethod, state);
74             }
75             catch (Exception ex)
76             {
77                 return TaskAsyncHelper.FromError(ex);
78             }
79         }
80 
81         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
82         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, T> endMethod, object state)83         public static Task<T> FromAsync<T>(Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, T> endMethod, object state)
84         {
85             try
86             {
87                 return Task.Factory.FromAsync<T>(beginMethod, endMethod, state);
88             }
89             catch (Exception ex)
90             {
91                 return TaskAsyncHelper.FromError<T>(ex);
92             }
93         }
94 
95         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Series(Func<object, Task>[] tasks, object[] state)96         public static Task Series(Func<object, Task>[] tasks, object[] state)
97         {
98             Task prev = TaskAsyncHelper.Empty;
99             Task finalTask = TaskAsyncHelper.Empty;
100 
101             for (int i = 0; i < tasks.Length; i++)
102             {
103                 prev = finalTask;
104                 finalTask = prev.Then(tasks[i], state[i]);
105             }
106 
107             return finalTask;
108         }
109 
110         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
111         public static TTask Catch<TTask>(this TTask task) where TTask : Task
112         {
113             return Catch(task, ex => { });
114         }
115 
116 #if PERFCOUNTERS
117         public static TTask Catch<TTask>(this TTask task, params IPerformanceCounter[] counters) where TTask : Task
118         {
119             return Catch(task, _ =>
120                 {
121                     if (counters == null)
122                     {
123                         return;
124                     }
125                     for (var i = 0; i < counters.Length; i++)
126                     {
127                         counters[i].Increment();
128                     }
129                 });
130         }
131 #endif
132 
133         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
134         public static TTask Catch<TTask>(this TTask task, Action<AggregateException, object> handler, object state) where TTask : Task
135         {
136             if (task != null && task.Status != TaskStatus.RanToCompletion)
137             {
138                 if (task.Status == TaskStatus.Faulted)
139                 {
140                     ExecuteOnFaulted(handler, state, task.Exception);
141                 }
142                 else
143                 {
144                     AttachFaultedContinuation<TTask>(task, handler, state);
145                 }
146             }
147 
148             return task;
149         }
150 
151         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
152         private static void AttachFaultedContinuation<TTask>(TTask task, Action<AggregateException, object> handler, object state) where TTask : Task
153         {
154             task.ContinueWith(innerTask =>
155             {
156                 ExecuteOnFaulted(handler, state, innerTask.Exception);
157             },
158             TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
159         }
160 
161         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
ExecuteOnFaulted(Action<AggregateException, object> handler, object state, AggregateException exception)162         private static void ExecuteOnFaulted(Action<AggregateException, object> handler, object state, AggregateException exception)
163         {
164             // observe Exception
165 #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE
166             Trace.TraceError("SignalR exception thrown by Task: {0}", exception);
167 #endif
168             handler(exception, state);
169         }
170 
171         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
172         public static TTask Catch<TTask>(this TTask task, Action<AggregateException> handler) where TTask : Task
173         {
174             return task.Catch((ex, state) => ((Action<AggregateException>)state).Invoke(ex),
175                               handler);
176         }
177 
178         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
179         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
ContinueWithNotComplete(this Task task, Action action)180         public static Task ContinueWithNotComplete(this Task task, Action action)
181         {
182             switch (task.Status)
183             {
184                 case TaskStatus.Faulted:
185                 case TaskStatus.Canceled:
186                     try
187                     {
188                         action();
189                         return task;
190                     }
191                     catch (Exception e)
192                     {
193                         return FromError(e);
194                     }
195                 case TaskStatus.RanToCompletion:
196                     return task;
197                 default:
198                     var tcs = new TaskCompletionSource<object>();
199 
200                     task.ContinueWith(t =>
201                     {
202                         if (t.IsFaulted || t.IsCanceled)
203                         {
204                             try
205                             {
206                                 action();
207 
208                                 if (t.IsFaulted)
209                                 {
210                                     tcs.TrySetUnwrappedException(t.Exception);
211                                 }
212                                 else
213                                 {
214                                     tcs.TrySetCanceled();
215                                 }
216                             }
217                             catch (Exception e)
218                             {
219                                 tcs.TrySetException(e);
220                             }
221                         }
222                         else
223                         {
224                             tcs.TrySetResult(null);
225                         }
226                     },
227                     TaskContinuationOptions.ExecuteSynchronously);
228 
229                     return tcs.Task;
230             }
231         }
232 
233         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs)234         public static void ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs)
235         {
236             task.ContinueWith(t =>
237             {
238                 if (t.IsFaulted)
239                 {
240                     tcs.SetUnwrappedException(t.Exception);
241                 }
242                 else if (t.IsCanceled)
243                 {
244                     tcs.SetCanceled();
245                 }
246             },
247             TaskContinuationOptions.NotOnRanToCompletion);
248         }
249 
250         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
ContinueWith(this Task task, TaskCompletionSource<object> tcs)251         public static void ContinueWith(this Task task, TaskCompletionSource<object> tcs)
252         {
253             task.ContinueWith(t =>
254             {
255                 if (t.IsFaulted)
256                 {
257                     tcs.TrySetUnwrappedException(t.Exception);
258                 }
259                 else if (t.IsCanceled)
260                 {
261                     tcs.TrySetCanceled();
262                 }
263                 else
264                 {
265                     tcs.TrySetResult(null);
266                 }
267             },
268             TaskContinuationOptions.ExecuteSynchronously);
269         }
270 
271         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
ContinueWith(this Task<T> task, TaskCompletionSource<T> tcs)272         public static void ContinueWith<T>(this Task<T> task, TaskCompletionSource<T> tcs)
273         {
274             task.ContinueWith(t =>
275             {
276                 if (t.IsFaulted)
277                 {
278                     tcs.TrySetUnwrappedException(t.Exception);
279                 }
280                 else if (t.IsCanceled)
281                 {
282                     tcs.TrySetCanceled();
283                 }
284                 else
285                 {
286                     tcs.TrySetResult(t.Result);
287                 }
288             });
289         }
290 
291         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Return(this Task[] tasks)292         public static Task Return(this Task[] tasks)
293         {
294             return Then(tasks, () => { });
295         }
296 
297         // Then extesions
298         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Action successor)299         public static Task Then(this Task task, Action successor)
300         {
301             switch (task.Status)
302             {
303                 case TaskStatus.Faulted:
304                 case TaskStatus.Canceled:
305                     return task;
306 
307                 case TaskStatus.RanToCompletion:
308                     return FromMethod(successor);
309 
310                 default:
311                     return RunTask(task, successor);
312             }
313         }
314 
315         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Func<TResult> successor)316         public static Task<TResult> Then<TResult>(this Task task, Func<TResult> successor)
317         {
318             switch (task.Status)
319             {
320                 case TaskStatus.Faulted:
321                     return FromError<TResult>(task.Exception);
322 
323                 case TaskStatus.Canceled:
324                     return Canceled<TResult>();
325 
326                 case TaskStatus.RanToCompletion:
327                     return FromMethod(successor);
328 
329                 default:
330                     return TaskRunners<object, TResult>.RunTask(task, successor);
331             }
332         }
333 
334         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task[] tasks, Action successor)335         public static Task Then(this Task[] tasks, Action successor)
336         {
337             if (tasks.Length == 0)
338             {
339                 return FromMethod(successor);
340             }
341 
342             var tcs = new TaskCompletionSource<object>();
343             Task.Factory.ContinueWhenAll(tasks, completedTasks =>
344             {
345                 var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted);
346                 if (faulted != null)
347                 {
348                     tcs.SetUnwrappedException(faulted.Exception);
349                     return;
350                 }
351                 var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled);
352                 if (cancelled != null)
353                 {
354                     tcs.SetCanceled();
355                     return;
356                 }
357 
358                 successor();
359                 tcs.SetResult(null);
360             });
361 
362             return tcs.Task;
363         }
364 
365         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Action<T1> successor, T1 arg1)366         public static Task Then<T1>(this Task task, Action<T1> successor, T1 arg1)
367         {
368             switch (task.Status)
369             {
370                 case TaskStatus.Faulted:
371                 case TaskStatus.Canceled:
372                     return task;
373 
374                 case TaskStatus.RanToCompletion:
375                     return FromMethod(successor, arg1);
376 
377                 default:
378                     return GenericDelegates<object, object, T1, object>.ThenWithArgs(task, successor, arg1);
379             }
380         }
381 
382         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)383         public static Task Then<T1, T2>(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)
384         {
385             switch (task.Status)
386             {
387                 case TaskStatus.Faulted:
388                 case TaskStatus.Canceled:
389                     return task;
390 
391                 case TaskStatus.RanToCompletion:
392                     return FromMethod(successor, arg1, arg2);
393 
394                 default:
395                     return GenericDelegates<object, object, T1, T2>.ThenWithArgs(task, successor, arg1, arg2);
396             }
397         }
398 
399         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Func<T1, Task> successor, T1 arg1)400         public static Task Then<T1>(this Task task, Func<T1, Task> successor, T1 arg1)
401         {
402             switch (task.Status)
403             {
404                 case TaskStatus.Faulted:
405                 case TaskStatus.Canceled:
406                     return task;
407 
408                 case TaskStatus.RanToCompletion:
409                     return FromMethod(successor, arg1);
410 
411                 default:
412                     return GenericDelegates<object, Task, T1, object>.ThenWithArgs(task, successor, arg1)
413                                                                      .FastUnwrap();
414             }
415         }
416 
417         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)418         public static Task Then<T1, T2>(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)
419         {
420             switch (task.Status)
421             {
422                 case TaskStatus.Faulted:
423                 case TaskStatus.Canceled:
424                     return task;
425 
426                 case TaskStatus.RanToCompletion:
427                     return FromMethod(successor, arg1, arg2);
428 
429                 default:
430                     return GenericDelegates<object, Task, T1, T2>.ThenWithArgs(task, successor, arg1, arg2)
431                                                                  .FastUnwrap();
432             }
433         }
434 
435         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<T> task, Func<T, Task<TResult>> successor)436         public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> successor)
437         {
438             switch (task.Status)
439             {
440                 case TaskStatus.Faulted:
441                     return FromError<TResult>(task.Exception);
442 
443                 case TaskStatus.Canceled:
444                     return Canceled<TResult>();
445 
446                 case TaskStatus.RanToCompletion:
447                     return FromMethod(successor, task.Result);
448 
449                 default:
450                     return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result))
451                                                         .FastUnwrap();
452             }
453         }
454 
455         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<T> task, Func<T, TResult> successor)456         public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> successor)
457         {
458             switch (task.Status)
459             {
460                 case TaskStatus.Faulted:
461                     return FromError<TResult>(task.Exception);
462 
463                 case TaskStatus.Canceled:
464                     return Canceled<TResult>();
465 
466                 case TaskStatus.RanToCompletion:
467                     return FromMethod(successor, task.Result);
468 
469                 default:
470                     return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result));
471             }
472         }
473 
474         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1)475         public static Task<TResult> Then<T, T1, TResult>(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1)
476         {
477             switch (task.Status)
478             {
479                 case TaskStatus.Faulted:
480                     return FromError<TResult>(task.Exception);
481 
482                 case TaskStatus.Canceled:
483                     return Canceled<TResult>();
484 
485                 case TaskStatus.RanToCompletion:
486                     return FromMethod(successor, task.Result, arg1);
487 
488                 default:
489                     return GenericDelegates<T, TResult, T1, object>.ThenWithArgs(task, successor, arg1);
490             }
491         }
492 
493         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Func<Task> successor)494         public static Task Then(this Task task, Func<Task> successor)
495         {
496             switch (task.Status)
497             {
498                 case TaskStatus.Faulted:
499                 case TaskStatus.Canceled:
500                     return task;
501 
502                 case TaskStatus.RanToCompletion:
503                     return FromMethod(successor);
504 
505                 default:
506                     return TaskRunners<object, Task>.RunTask(task, successor)
507                                                     .FastUnwrap();
508             }
509         }
510 
511         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task task, Func<Task<TResult>> successor)512         public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> successor)
513         {
514             switch (task.Status)
515             {
516                 case TaskStatus.Faulted:
517                     return FromError<TResult>(task.Exception);
518 
519                 case TaskStatus.Canceled:
520                     return Canceled<TResult>();
521 
522                 case TaskStatus.RanToCompletion:
523                     return FromMethod(successor);
524 
525                 default:
526                     return TaskRunners<object, Task<TResult>>.RunTask(task, successor)
527                                                              .FastUnwrap();
528             }
529         }
530 
531         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<TResult> task, Action<TResult> successor)532         public static Task Then<TResult>(this Task<TResult> task, Action<TResult> successor)
533         {
534             switch (task.Status)
535             {
536                 case TaskStatus.Faulted:
537                 case TaskStatus.Canceled:
538                     return task;
539 
540                 case TaskStatus.RanToCompletion:
541                     return FromMethod(successor, task.Result);
542 
543                 default:
544                     return TaskRunners<TResult, object>.RunTask(task, successor);
545             }
546         }
547 
548         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<TResult> task, Func<TResult, Task> successor)549         public static Task Then<TResult>(this Task<TResult> task, Func<TResult, Task> successor)
550         {
551             switch (task.Status)
552             {
553                 case TaskStatus.Faulted:
554                 case TaskStatus.Canceled:
555                     return task;
556 
557                 case TaskStatus.RanToCompletion:
558                     return FromMethod(successor, task.Result);
559 
560                 default:
561                     return TaskRunners<TResult, Task>.RunTask(task, t => successor(t.Result))
562                                                      .FastUnwrap();
563             }
564         }
565 
566         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Then(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1)567         public static Task<TResult> Then<TResult, T1>(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1)
568         {
569             switch (task.Status)
570             {
571                 case TaskStatus.Faulted:
572                 case TaskStatus.Canceled:
573                     return task;
574 
575                 case TaskStatus.RanToCompletion:
576                     return FromMethod(successor, task, arg1);
577 
578                 default:
579                     return GenericDelegates<TResult, Task<TResult>, T1, object>.ThenWithArgs(task, successor, arg1)
580                                                                                .FastUnwrap();
581             }
582         }
583 
584         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed to the caller")]
585         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Finally(this Task task, Action<object> next, object state)586         public static Task Finally(this Task task, Action<object> next, object state)
587         {
588             try
589             {
590                 switch (task.Status)
591                 {
592                     case TaskStatus.Faulted:
593                     case TaskStatus.Canceled:
594                         next(state);
595                         return task;
596                     case TaskStatus.RanToCompletion:
597                         return FromMethod(next, state);
598 
599                     default:
600                         return RunTaskSynchronously(task, next, state, onlyOnSuccess: false);
601                 }
602             }
603             catch (Exception ex)
604             {
605                 return FromError(ex);
606             }
607         }
608 
609         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
RunSynchronously(this Task task, Action successor)610         public static Task RunSynchronously(this Task task, Action successor)
611         {
612             switch (task.Status)
613             {
614                 case TaskStatus.Faulted:
615                 case TaskStatus.Canceled:
616                     return task;
617 
618                 case TaskStatus.RanToCompletion:
619                     return FromMethod(successor);
620 
621                 default:
622                     return RunTaskSynchronously(task, state => ((Action)state).Invoke(), successor);
623             }
624         }
625 
626         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
FastUnwrap(this Task<Task> task)627         public static Task FastUnwrap(this Task<Task> task)
628         {
629             var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null;
630             return innerTask ?? task.Unwrap();
631         }
632 
633         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
FastUnwrap(this Task<Task<T>> task)634         public static Task<T> FastUnwrap<T>(this Task<Task<T>> task)
635         {
636             var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null;
637             return innerTask ?? task.Unwrap();
638         }
639 
640         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Delay(TimeSpan timeOut)641         public static Task Delay(TimeSpan timeOut)
642         {
643 #if NETFX_CORE
644             return Task.Delay(timeOut);
645 #else
646             var tcs = new TaskCompletionSource<object>();
647 
648             var timer = new Timer(tcs.SetResult,
649             null,
650             timeOut,
651             TimeSpan.FromMilliseconds(-1));
652 
653             return tcs.Task.ContinueWith(_ =>
654             {
655                 timer.Dispose();
656             },
657             TaskContinuationOptions.ExecuteSynchronously);
658 #endif
659         }
660 
661         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
662         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Action func)663         public static Task FromMethod(Action func)
664         {
665             try
666             {
667                 func();
668                 return Empty;
669             }
670             catch (Exception ex)
671             {
672                 return FromError(ex);
673             }
674         }
675 
676         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
677         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Action<T1> func, T1 arg)678         public static Task FromMethod<T1>(Action<T1> func, T1 arg)
679         {
680             try
681             {
682                 func(arg);
683                 return Empty;
684             }
685             catch (Exception ex)
686             {
687                 return FromError(ex);
688             }
689         }
690 
691         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
692         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Action<T1, T2> func, T1 arg1, T2 arg2)693         public static Task FromMethod<T1, T2>(Action<T1, T2> func, T1 arg1, T2 arg2)
694         {
695             try
696             {
697                 func(arg1, arg2);
698                 return Empty;
699             }
700             catch (Exception ex)
701             {
702                 return FromError(ex);
703             }
704         }
705 
706         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
707         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<Task> func)708         public static Task FromMethod(Func<Task> func)
709         {
710             try
711             {
712                 return func();
713             }
714             catch (Exception ex)
715             {
716                 return FromError(ex);
717             }
718         }
719 
720         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
721         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<Task<TResult>> func)722         public static Task<TResult> FromMethod<TResult>(Func<Task<TResult>> func)
723         {
724             try
725             {
726                 return func();
727             }
728             catch (Exception ex)
729             {
730                 return FromError<TResult>(ex);
731             }
732         }
733 
734         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
735         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<TResult> func)736         public static Task<TResult> FromMethod<TResult>(Func<TResult> func)
737         {
738             try
739             {
740                 return FromResult<TResult>(func());
741             }
742             catch (Exception ex)
743             {
744                 return FromError<TResult>(ex);
745             }
746         }
747 
748         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
749         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, Task> func, T1 arg)750         public static Task FromMethod<T1>(Func<T1, Task> func, T1 arg)
751         {
752             try
753             {
754                 return func(arg);
755             }
756             catch (Exception ex)
757             {
758                 return FromError(ex);
759             }
760         }
761 
762         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
763         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, T2, Task> func, T1 arg1, T2 arg2)764         public static Task FromMethod<T1, T2>(Func<T1, T2, Task> func, T1 arg1, T2 arg2)
765         {
766             try
767             {
768                 return func(arg1, arg2);
769             }
770             catch (Exception ex)
771             {
772                 return FromError(ex);
773             }
774         }
775 
776         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
777         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, Task<TResult>> func, T1 arg)778         public static Task<TResult> FromMethod<T1, TResult>(Func<T1, Task<TResult>> func, T1 arg)
779         {
780             try
781             {
782                 return func(arg);
783             }
784             catch (Exception ex)
785             {
786                 return FromError<TResult>(ex);
787             }
788         }
789 
790         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
791         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, TResult> func, T1 arg)792         public static Task<TResult> FromMethod<T1, TResult>(Func<T1, TResult> func, T1 arg)
793         {
794             try
795             {
796                 return FromResult<TResult>(func(arg));
797             }
798             catch (Exception ex)
799             {
800                 return FromError<TResult>(ex);
801             }
802         }
803 
804         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
805         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, T2, Task<TResult>> func, T1 arg1, T2 arg2)806         public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, Task<TResult>> func, T1 arg1, T2 arg2)
807         {
808             try
809             {
810                 return func(arg1, arg2);
811             }
812             catch (Exception ex)
813             {
814                 return FromError<TResult>(ex);
815             }
816         }
817 
818         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
819         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
FromMethod(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)820         public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
821         {
822             try
823             {
824                 return FromResult<TResult>(func(arg1, arg2));
825             }
826             catch (Exception ex)
827             {
828                 return FromError<TResult>(ex);
829             }
830         }
831 
832         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
FromResult(T value)833         public static Task<T> FromResult<T>(T value)
834         {
835             var tcs = new TaskCompletionSource<T>();
836             tcs.SetResult(value);
837             return tcs.Task;
838         }
839 
840         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
FromError(Exception e)841         internal static Task FromError(Exception e)
842         {
843             return FromError<object>(e);
844         }
845 
846         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
FromError(Exception e)847         internal static Task<T> FromError<T>(Exception e)
848         {
849             var tcs = new TaskCompletionSource<T>();
850             tcs.SetUnwrappedException<T>(e);
851             return tcs.Task;
852         }
853 
854         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
SetUnwrappedException(this TaskCompletionSource<T> tcs, Exception e)855         internal static void SetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e)
856         {
857             var aggregateException = e as AggregateException;
858             if (aggregateException != null)
859             {
860                 tcs.SetException(aggregateException.InnerExceptions);
861             }
862             else
863             {
864                 tcs.SetException(e);
865             }
866         }
867 
868         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
TrySetUnwrappedException(this TaskCompletionSource<T> tcs, Exception e)869         internal static bool TrySetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e)
870         {
871             var aggregateException = e as AggregateException;
872             if (aggregateException != null)
873             {
874                 return tcs.TrySetException(aggregateException.InnerExceptions);
875             }
876             else
877             {
878                 return tcs.TrySetException(e);
879             }
880         }
881 
882         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Canceled()883         private static Task Canceled()
884         {
885             var tcs = new TaskCompletionSource<object>();
886             tcs.SetCanceled();
887             return tcs.Task;
888         }
889 
890         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
Canceled()891         private static Task<T> Canceled<T>()
892         {
893             var tcs = new TaskCompletionSource<T>();
894             tcs.SetCanceled();
895             return tcs.Task;
896         }
897 
898         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
RunTask(Task task, Action successor)899         private static Task RunTask(Task task, Action successor)
900         {
901             var tcs = new TaskCompletionSource<object>();
902             task.ContinueWith(t =>
903             {
904                 if (t.IsFaulted)
905                 {
906                     tcs.SetUnwrappedException(t.Exception);
907                 }
908                 else if (t.IsCanceled)
909                 {
910                     tcs.SetCanceled();
911                 }
912                 else
913                 {
914                     try
915                     {
916                         successor();
917                         tcs.SetResult(null);
918                     }
919                     catch (Exception ex)
920                     {
921                         tcs.SetUnwrappedException(ex);
922                     }
923                 }
924             });
925 
926             return tcs.Task;
927         }
928 
929         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
930         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
RunTaskSynchronously(Task task, Action<object> next, object state, bool onlyOnSuccess = true)931         private static Task RunTaskSynchronously(Task task, Action<object> next, object state, bool onlyOnSuccess = true)
932         {
933             var tcs = new TaskCompletionSource<object>();
934             task.ContinueWith(t =>
935             {
936                 try
937                 {
938                     if (t.IsFaulted)
939                     {
940                         if (!onlyOnSuccess)
941                         {
942                             next(state);
943                         }
944 
945                         tcs.SetUnwrappedException(t.Exception);
946                     }
947                     else if (t.IsCanceled)
948                     {
949                         if (!onlyOnSuccess)
950                         {
951                             next(state);
952                         }
953 
954                         tcs.SetCanceled();
955                     }
956                     else
957                     {
958                         next(state);
959                         tcs.SetResult(null);
960                     }
961                 }
962                 catch (Exception ex)
963                 {
964                     tcs.SetUnwrappedException(ex);
965                 }
966             },
967             TaskContinuationOptions.ExecuteSynchronously);
968 
969             return tcs.Task;
970         }
971 
972         private static class TaskRunners<T, TResult>
973         {
974             [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
RunTask(Task<T> task, Action<T> successor)975             internal static Task RunTask(Task<T> task, Action<T> successor)
976             {
977                 var tcs = new TaskCompletionSource<object>();
978                 task.ContinueWith(t =>
979                 {
980                     if (t.IsFaulted)
981                     {
982                         tcs.SetUnwrappedException(t.Exception);
983                     }
984                     else if (t.IsCanceled)
985                     {
986                         tcs.SetCanceled();
987                     }
988                     else
989                     {
990                         try
991                         {
992                             successor(t.Result);
993                             tcs.SetResult(null);
994                         }
995                         catch (Exception ex)
996                         {
997                             tcs.SetUnwrappedException(ex);
998                         }
999                     }
1000                 });
1001 
1002                 return tcs.Task;
1003             }
1004 
1005             [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
RunTask(Task task, Func<TResult> successor)1006             internal static Task<TResult> RunTask(Task task, Func<TResult> successor)
1007             {
1008                 var tcs = new TaskCompletionSource<TResult>();
1009                 task.ContinueWith(t =>
1010                 {
1011                     if (t.IsFaulted)
1012                     {
1013                         tcs.SetUnwrappedException(t.Exception);
1014                     }
1015                     else if (t.IsCanceled)
1016                     {
1017                         tcs.SetCanceled();
1018                     }
1019                     else
1020                     {
1021                         try
1022                         {
1023                             tcs.SetResult(successor());
1024                         }
1025                         catch (Exception ex)
1026                         {
1027                             tcs.SetUnwrappedException(ex);
1028                         }
1029                     }
1030                 });
1031 
1032                 return tcs.Task;
1033             }
1034 
1035             [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
RunTask(Task<T> task, Func<Task<T>, TResult> successor)1036             internal static Task<TResult> RunTask(Task<T> task, Func<Task<T>, TResult> successor)
1037             {
1038                 var tcs = new TaskCompletionSource<TResult>();
1039                 task.ContinueWith(t =>
1040                 {
1041                     if (task.IsFaulted)
1042                     {
1043                         tcs.SetUnwrappedException(t.Exception);
1044                     }
1045                     else if (task.IsCanceled)
1046                     {
1047                         tcs.SetCanceled();
1048                     }
1049                     else
1050                     {
1051                         try
1052                         {
1053                             tcs.SetResult(successor(t));
1054                         }
1055                         catch (Exception ex)
1056                         {
1057                             tcs.SetUnwrappedException(ex);
1058                         }
1059                     }
1060                 });
1061 
1062                 return tcs.Task;
1063             }
1064         }
1065 
1066         private static class GenericDelegates<T, TResult, T1, T2>
1067         {
ThenWithArgs(Task task, Action<T1> successor, T1 arg1)1068             internal static Task ThenWithArgs(Task task, Action<T1> successor, T1 arg1)
1069             {
1070                 return RunTask(task, () => successor(arg1));
1071             }
1072 
ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)1073             internal static Task ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)
1074             {
1075                 return RunTask(task, () => successor(arg1, arg2));
1076             }
1077 
ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1)1078             internal static Task<TResult> ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1)
1079             {
1080                 return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1));
1081             }
1082 
ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2)1083             internal static Task<TResult> ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2)
1084             {
1085                 return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1, arg2));
1086             }
1087 
ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1)1088             internal static Task<TResult> ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1)
1089             {
1090                 return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result, arg1));
1091             }
1092 
ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1)1093             internal static Task<Task> ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1)
1094             {
1095                 return TaskRunners<object, Task>.RunTask(task, () => successor(arg1));
1096             }
1097 
ThenWithArgs(Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)1098             internal static Task<Task> ThenWithArgs(Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)
1099             {
1100                 return TaskRunners<object, Task>.RunTask(task, () => successor(arg1, arg2));
1101             }
1102 
ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1)1103             internal static Task<Task<TResult>> ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1)
1104             {
1105                 return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result, arg1));
1106             }
1107 
ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1)1108             internal static Task<Task<T>> ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1)
1109             {
1110                 return TaskRunners<T, Task<T>>.RunTask(task, t => successor(t, arg1));
1111             }
1112         }
1113 
1114         private static class TaskCache<T>
1115         {
1116             public static Task<T> Empty = MakeTask<T>(default(T));
1117         }
1118     }
1119 }
1120