77//--------------------------------------------------------------------------
88
99using System . Linq ;
10- using System . Windows . Threading ;
1110
1211namespace System . Threading . Tasks
1312{
1413 /// <summary>Extensions methods for Task.</summary>
1514 /// <preliminary/>
1615 internal static class TaskExtrasExtensions
1716 {
18- #region ContinueWith accepting TaskFactory
19- /// <summary>Creates a continuation task using the specified TaskFactory.</summary>
20- /// <param name="task">The antecedent Task.</param>
21- /// <param name="continuationAction">The continuation action.</param>
22- /// <param name="factory">The TaskFactory.</param>
23- /// <returns>A continuation task.</returns>
24- public static Task ContinueWith (
25- this Task task , Action < Task > continuationAction , TaskFactory factory )
26- {
27- return task . ContinueWith ( continuationAction , factory . CancellationToken , factory . ContinuationOptions , factory . Scheduler ) ;
28- }
29-
30- /// <summary>Creates a continuation task using the specified TaskFactory.</summary>
31- /// <param name="task">The antecedent Task.</param>
32- /// <param name="continuationFunction">The continuation function.</param>
33- /// <param name="factory">The TaskFactory.</param>
34- /// <returns>A continuation task.</returns>
35- public static Task < TResult > ContinueWith < TResult > (
36- this Task task , Func < Task , TResult > continuationFunction , TaskFactory factory )
37- {
38- return task . ContinueWith ( continuationFunction , factory . CancellationToken , factory . ContinuationOptions , factory . Scheduler ) ;
39- }
40- #endregion
41-
42- #region ContinueWith accepting TaskFactory<TResult>
43- /// <summary>Creates a continuation task using the specified TaskFactory.</summary>
44- /// <param name="task">The antecedent Task.</param>
45- /// <param name="continuationAction">The continuation action.</param>
46- /// <param name="factory">The TaskFactory.</param>
47- /// <returns>A continuation task.</returns>
48- public static Task ContinueWith < TResult > (
49- this Task < TResult > task , Action < Task < TResult > > continuationAction , TaskFactory < TResult > factory )
50- {
51- return task . ContinueWith ( continuationAction , factory . CancellationToken , factory . ContinuationOptions , factory . Scheduler ) ;
52- }
53-
54- /// <summary>Creates a continuation task using the specified TaskFactory.</summary>
55- /// <param name="task">The antecedent Task.</param>
56- /// <param name="continuationFunction">The continuation function.</param>
57- /// <param name="factory">The TaskFactory.</param>
58- /// <returns>A continuation task.</returns>
59- public static Task < TNewResult > ContinueWith < TResult , TNewResult > (
60- this Task < TResult > task , Func < Task < TResult > , TNewResult > continuationFunction , TaskFactory < TResult > factory )
61- {
62- return task . ContinueWith ( continuationFunction , factory . CancellationToken , factory . ContinuationOptions , factory . Scheduler ) ;
63- }
64- #endregion
65-
66- #region ToAsync(AsyncCallback, object)
67- /// <summary>
68- /// Creates a Task that represents the completion of another Task, and
69- /// that schedules an AsyncCallback to run upon completion.
70- /// </summary>
71- /// <param name="task">The antecedent Task.</param>
72- /// <param name="callback">The AsyncCallback to run.</param>
73- /// <param name="state">The object state to use with the AsyncCallback.</param>
74- /// <returns>The new task.</returns>
75- public static Task ToAsync ( this Task task , AsyncCallback callback , object state )
76- {
77- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
78-
79- var tcs = new TaskCompletionSource < object > ( state ) ;
80- task . ContinueWith ( _ =>
81- {
82- tcs . SetFromTask ( task ) ;
83- if ( callback != null ) callback ( tcs . Task ) ;
84- } ) ;
85- return tcs . Task ;
86- }
87-
88- /// <summary>
89- /// Creates a Task that represents the completion of another Task, and
90- /// that schedules an AsyncCallback to run upon completion.
91- /// </summary>
92- /// <param name="task">The antecedent Task.</param>
93- /// <param name="callback">The AsyncCallback to run.</param>
94- /// <param name="state">The object state to use with the AsyncCallback.</param>
95- /// <returns>The new task.</returns>
96- public static Task < TResult > ToAsync < TResult > ( this Task < TResult > task , AsyncCallback callback , object state )
97- {
98- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
99-
100- var tcs = new TaskCompletionSource < TResult > ( state ) ;
101- task . ContinueWith ( _ =>
102- {
103- tcs . SetFromTask ( task ) ;
104- if ( callback != null ) callback ( tcs . Task ) ;
105- } ) ;
106- return tcs . Task ;
107- }
108- #endregion
109-
11017 #region Exception Handling
111- /// <summary>Suppresses default exception handling of a Task that would otherwise re-raise the exception on the finalizer thread.</summary>
112- /// <param name="task">The Task to be monitored.</param>
113- /// <returns>The original Task.</returns>
114- public static Task IgnoreExceptions ( this Task task )
115- {
116- task . ContinueWith ( t => { var ignored = t . Exception ; } ,
117- CancellationToken . None ,
118- TaskContinuationOptions . ExecuteSynchronously | TaskContinuationOptions . OnlyOnFaulted ,
119- TaskScheduler . Default ) ;
120- return task ;
121- }
122-
123- /// <summary>Suppresses default exception handling of a Task that would otherwise re-raise the exception on the finalizer thread.</summary>
124- /// <param name="task">The Task to be monitored.</param>
125- /// <returns>The original Task.</returns>
126- public static Task < T > IgnoreExceptions < T > ( this Task < T > task )
127- {
128- return ( Task < T > ) ( ( Task ) task ) . IgnoreExceptions ( ) ;
129- }
130-
131- /// <summary>Fails immediately when an exception is encountered.</summary>
132- /// <param name="task">The Task to be monitored.</param>
133- /// <returns>The original Task.</returns>
134- public static Task FailFastOnException ( this Task task )
135- {
136- #if NET35
137- Action < Task > continuation = t => Environment . FailFast ( "A task faulted." ) ;
138- #else
139- Action < Task > continuation = t => Environment . FailFast ( "A task faulted." , t . Exception ) ;
140- #endif
141-
142- task . ContinueWith ( continuation ,
143- CancellationToken . None ,
144- TaskContinuationOptions . ExecuteSynchronously | TaskContinuationOptions . OnlyOnFaulted ,
145- TaskScheduler . Default ) ;
146- return task ;
147- }
148-
149- /// <summary>Fails immediately when an exception is encountered.</summary>
150- /// <param name="task">The Task to be monitored.</param>
151- /// <returns>The original Task.</returns>
152- public static Task < T > FailFastOnException < T > ( this Task < T > task )
153- {
154- return ( Task < T > ) ( ( Task ) task ) . FailFastOnException ( ) ;
155- }
156-
15718 /// <summary>Propagates any exceptions that occurred on the specified task.</summary>
15819 /// <param name="task">The Task whose exceptions are to be propagated.</param>
15920 public static void PropagateExceptions ( this Task task )
@@ -172,141 +33,5 @@ public static void PropagateExceptions(this Task [] tasks)
17233 Task . WaitAll ( tasks ) ;
17334 }
17435 #endregion
175-
176- #if ! NET35
177- #region Observables
178- /// <summary>Creates an IObservable that represents the completion of a Task.</summary>
179- /// <typeparam name="TResult">Specifies the type of data returned by the Task.</typeparam>
180- /// <param name="task">The Task to be represented as an IObservable.</param>
181- /// <returns>An IObservable that represents the completion of the Task.</returns>
182- public static IObservable < TResult > ToObservable < TResult > ( this Task < TResult > task )
183- {
184- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
185- return new TaskObservable < TResult > { _task = task } ;
186- }
187-
188- /// <summary>An implementation of IObservable that wraps a Task.</summary>
189- /// <typeparam name="TResult">The type of data returned by the task.</typeparam>
190- private class TaskObservable < TResult > : IObservable < TResult >
191- {
192- internal Task < TResult > _task ;
193-
194- public IDisposable Subscribe ( IObserver < TResult > observer )
195- {
196- // Validate arguments
197- if ( observer == null ) throw new ArgumentNullException ( "observer" ) ;
198-
199- // Support cancelling the continuation if the observer is unsubscribed
200- var cts = new CancellationTokenSource ( ) ;
201-
202- // Create a continuation to pass data along to the observer
203- _task . ContinueWith ( t =>
204- {
205- switch ( t . Status )
206- {
207- case TaskStatus . RanToCompletion :
208- observer . OnNext ( _task . Result ) ;
209- observer . OnCompleted ( ) ;
210- break ;
211-
212- case TaskStatus . Faulted :
213- observer . OnError ( _task . Exception ) ;
214- break ;
215-
216- case TaskStatus . Canceled :
217- observer . OnError ( new TaskCanceledException ( t ) ) ;
218- break ;
219- }
220- } , cts . Token ) ;
221-
222- // Support unsubscribe simply by canceling the continuation if it hasn't yet run
223- return new CancelOnDispose { Source = cts } ;
224- }
225- }
226-
227- /// <summary>Translate a call to IDisposable.Dispose to a CancellationTokenSource.Cancel.</summary>
228- private class CancelOnDispose : IDisposable
229- {
230- internal CancellationTokenSource Source ;
231- void IDisposable . Dispose ( ) { Source . Cancel ( ) ; }
232- }
233- #endregion
234- #endif
235-
236- #region Timeouts
237- /// <summary>Creates a new Task that mirrors the supplied task but that will be canceled after the specified timeout.</summary>
238- /// <param name="task">The task.</param>
239- /// <param name="timeout">The timeout.</param>
240- /// <returns>The new Task that may time out.</returns>
241- public static Task WithTimeout ( this Task task , TimeSpan timeout )
242- {
243- var result = new TaskCompletionSource < object > ( task . AsyncState ) ;
244- var timer = new Timer ( state => ( ( TaskCompletionSource < object > ) state ) . TrySetCanceled ( ) , result , timeout , TimeSpan . FromMilliseconds ( - 1 ) ) ;
245- task . ContinueWith ( t =>
246- {
247- timer . Dispose ( ) ;
248- result . TrySetFromTask ( t ) ;
249- } , TaskContinuationOptions . ExecuteSynchronously ) ;
250- return result . Task ;
251- }
252-
253- /// <summary>Creates a new Task that mirrors the supplied task but that will be canceled after the specified timeout.</summary>
254- /// <typeparam name="TResult">Specifies the type of data contained in the task.</typeparam>
255- /// <param name="task">The task.</param>
256- /// <param name="timeout">The timeout.</param>
257- /// <returns>The new Task that may time out.</returns>
258- public static Task < TResult > WithTimeout < TResult > ( this Task < TResult > task , TimeSpan timeout )
259- {
260- var result = new TaskCompletionSource < TResult > ( task . AsyncState ) ;
261- var timer = new Timer ( state => ( ( TaskCompletionSource < TResult > ) state ) . TrySetCanceled ( ) , result , timeout , TimeSpan . FromMilliseconds ( - 1 ) ) ;
262- task . ContinueWith ( t =>
263- {
264- timer . Dispose ( ) ;
265- result . TrySetFromTask ( t ) ;
266- } , TaskContinuationOptions . ExecuteSynchronously ) ;
267- return result . Task ;
268- }
269- #endregion
270-
271- #region Children
272- /// <summary>
273- /// Ensures that a parent task can't transition into a completed state
274- /// until the specified task has also completed, even if it's not
275- /// already a child task.
276- /// </summary>
277- /// <param name="task">The task to attach to the current task as a child.</param>
278- public static void AttachToParent ( this Task task )
279- {
280- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
281- task . ContinueWith ( t => t . Wait ( ) , CancellationToken . None ,
282- TaskContinuationOptions . AttachedToParent |
283- TaskContinuationOptions . ExecuteSynchronously , TaskScheduler . Default ) ;
284- }
285- #endregion
286-
287- #region Waiting
288- /// <summary>Waits for the task to complete execution, pumping in the meantime.</summary>
289- /// <param name="task">The task for which to wait.</param>
290- /// <remarks>This method is intended for usage with Windows Presentation Foundation.</remarks>
291- public static void WaitWithPumping ( this Task task )
292- {
293- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
294- var nestedFrame = new DispatcherFrame ( ) ;
295- task . ContinueWith ( _ => nestedFrame . Continue = false ) ;
296- Dispatcher . PushFrame ( nestedFrame ) ;
297- task . Wait ( ) ;
298- }
299-
300- /// <summary>Waits for the task to complete execution, returning the task's final status.</summary>
301- /// <param name="task">The task for which to wait.</param>
302- /// <returns>The completion status of the task.</returns>
303- /// <remarks>Unlike Wait, this method will not throw an exception if the task ends in the Faulted or Canceled state.</remarks>
304- public static TaskStatus WaitForCompletionStatus ( this Task task )
305- {
306- if ( task == null ) throw new ArgumentNullException ( "task" ) ;
307- ( ( IAsyncResult ) task ) . AsyncWaitHandle . WaitOne ( ) ;
308- return task . Status ;
309- }
310- #endregion
31136 }
312- }
37+ }
0 commit comments