@@ -5,6 +5,9 @@ namespace Open.Threading
55{
66 public static class TaskExtensions
77 {
8+ /// <summary>
9+ /// Returns true if the target Task has not yet run, is waiting, or is running, else returns false.
10+ /// </summary>
811 public static bool IsActive ( this Task target )
912 {
1013 if ( target == null )
@@ -18,83 +21,130 @@ public static bool IsActive(this Task target)
1821 case TaskStatus . WaitingForChildrenToComplete :
1922 case TaskStatus . WaitingToRun :
2023 return true ;
21- case TaskStatus . Canceled :
22- case TaskStatus . Faulted :
23- case TaskStatus . RanToCompletion :
24- return false ;
24+ // case TaskStatus.Canceled:
25+ // case TaskStatus.Faulted:
26+ // case TaskStatus.RanToCompletion:
27+ // return false;
2528 }
2629
2730 return false ;
2831 }
2932
30-
31-
32- public static Task OnFullfilled ( this Task target , Action action )
33+ /// <summary>
34+ /// Checks the status of the task and attempts to start it if waiting to start (TaskStatus.Created).
35+ /// </summary>
36+ /// <param name="scheduler">Optional scheduler to use.</param>
37+ /// <returns>True if start attempt was successful.</returns>
38+ public static bool EnsureStarted ( this Task target , TaskScheduler scheduler = null )
3339 {
34- return target . ContinueWith ( task =>
35- {
36- if ( task . IsCompleted ) action ( ) ;
37- } ) ;
38- }
40+ if ( target == null ) throw new NullReferenceException ( ) ;
3941
40- public static Task OnFullfilled < T > ( this Task target , Func < T > action )
41- {
42- return target . ContinueWith ( task =>
42+ if ( target . Status == TaskStatus . Created )
4343 {
44- if ( task . IsCompleted ) action ( ) ;
45- } ) ;
44+ try
45+ {
46+ if ( scheduler == null )
47+ target . Start ( ) ;
48+ else
49+ target . Start ( scheduler ) ;
50+
51+ return true ;
52+ }
53+ catch ( InvalidOperationException )
54+ {
55+ // Even though we've checked the status, it's possible it could have been started. We can't guarantee proper handling without a trap here.
56+ if ( target . Status == TaskStatus . Created )
57+ throw ; // Something wierd must have happened if we arrived here.
58+ }
59+ }
60+
61+ return false ;
4662 }
4763
48- public static Task < T > OnFullfilled < T > ( this Task < T > target , Action < T > action )
64+ /// <summary>
65+ /// Utility method that can be chained with other methods for reacting to Task results. Only invokes the action if completed and not cancelled.
66+ /// </summary>
67+ /// <typeparam name="TTask">The return type is the same as the target.</typeparam>
68+ /// <param name="action">The action to perform if fullfulled.</param>
69+ /// <returns>The target object. Allows for method chaining.</returns>
70+ public static TTask OnFullfilled < TTask > ( this TTask target , Action action )
71+ where TTask : Task
4972 {
50- return target . ContinueWith ( task =>
73+ target . ContinueWith ( task =>
5174 {
52- if ( task . IsCompleted ) action ( task . Result ) ;
53- return task . Result ;
75+ if ( task . IsCompleted && ! task . IsCanceled ) action ( ) ;
5476 } ) ;
77+
78+ return target ;
5579 }
5680
57- // Tasks don't behave like promises so even though this seems like we should call this "Catch", it's not doing that and a real catch statment needs to be wrapped around a wait call.
58- public static Task OnFaulted ( this Task target , Action < Exception > action )
81+ /// <summary>
82+ /// Utility method that can be chained with other methods for reacting to Task results. Only invokes the action if completed and not cancelled.
83+ /// </summary>
84+ /// <typeparam name="TTask">The return type is the same as the target.</typeparam>
85+ /// <param name="action">The action to perform if fullfulled.</param>
86+ /// <returns>The target object. Allows for method chaining.</returns>
87+ public static TTask OnFullfilled < TTask , T > ( this TTask target , Func < T > action )
88+ where TTask : Task
5989 {
60- return target . ContinueWith ( task =>
90+ target . ContinueWith ( task =>
6191 {
62- if ( task . IsFaulted ) action ( task . Exception ) ;
92+ if ( task . IsCompleted && ! task . IsCanceled ) action ( ) ;
6393 } ) ;
94+
95+ return target ;
6496 }
6597
66- public static Task < T > OnFaulted < T > ( this Task < T > target , Action < Exception > action )
98+ /// <summary>
99+ /// Utility method that can be chained with other methods for reacting to Task results. Only invokes the action if faulted.
100+ /// </summary>
101+ /// <typeparam name="TTask">The return type is the same as the target.</typeparam>
102+ /// <param name="action">The action to perform if faulted.</param>
103+ /// <returns>The target object. Allows for method chaining.</returns>
104+ public static TTask OnFaulted < TTask > ( this TTask target , Action < Exception > action )
105+ where TTask : Task
67106 {
68- return target . ContinueWith ( task =>
107+ target . ContinueWith ( task =>
69108 {
70109 if ( task . IsFaulted ) action ( task . Exception ) ;
71- return task . Result ;
72110 } ) ;
73- }
74111
75- public static Task OnCancelled ( this Task target , Action action )
76- {
77- return target . ContinueWith ( task =>
78- {
79- if ( task . IsCanceled ) action ( ) ;
80- } ) ;
112+ return target ;
81113 }
82114
83- public static Task < T > OnCancelled < T > ( this Task < T > target , Action action )
115+
116+ /// <summary>
117+ /// Utility method that can be chained with other methods for reacting to Task results. Only invokes the action if cancelled.
118+ /// </summary>
119+ /// <typeparam name="TTask">The return type is the same as the target.</typeparam>
120+ /// <param name="action">The action to perform if cancelled.</param>
121+ /// <returns>The target object. Allows for method chaining.</returns>
122+ public static TTask OnCancelled < TTask > ( this TTask target , Action action )
123+ where TTask : Task
84124 {
85- return target . ContinueWith ( task =>
125+ target . ContinueWith ( task =>
86126 {
87- if ( task . IsCanceled ) action ( ) ;
88- return task . Result ;
127+ if ( ! task . IsCanceled ) action ( ) ;
89128 } ) ;
129+
130+ return target ;
90131 }
91132
92- public static Task OnCancelled < T > ( this Task target , Func < T > action )
133+ /// <summary>
134+ /// Utility method that can be chained with other methods for reacting to Task results. Only invokes the action if cancelled.
135+ /// </summary>
136+ /// <typeparam name="TTask">The return type is the same as the target.</typeparam>
137+ /// <param name="action">The action to perform if cancelled.</param>
138+ /// <returns>The target object. Allows for method chaining.</returns>
139+ public static TTask OnCancelled < TTask , T > ( this TTask target , Func < T > action )
140+ where TTask : Task
93141 {
94- return target . ContinueWith ( task =>
142+ target . ContinueWith ( task =>
95143 {
96- if ( task . IsCanceled ) action ( ) ;
144+ if ( ! task . IsCanceled ) action ( ) ;
97145 } ) ;
146+
147+ return target ;
98148 }
99149
100150 }
0 commit comments