3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
10 // <OWNER>[....]</OWNER>
12 // A task that produces a value.
14 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
17 using System.Collections.Generic;
19 using System.Runtime.CompilerServices;
20 using System.Runtime.ExceptionServices;
21 using System.Security;
22 using System.Security.Permissions;
23 using System.Threading;
24 using System.Diagnostics;
25 using System.Diagnostics.Contracts;
27 // Disable the "reference to volatile field not treated as volatile" error.
28 #pragma warning disable 0420
30 namespace System.Threading.Tasks
33 /// Represents an asynchronous operation that produces a result at some time in the future.
35 /// <typeparam name="TResult">
36 /// The type of the result produced by this <see cref="Task{TResult}"/>.
40 /// <see cref="Task{TResult}"/> instances may be created in a variety of ways. The most common approach is by
41 /// using the task's <see cref="Factory"/> property to retrieve a <see
42 /// cref="System.Threading.Tasks.TaskFactory{TResult}"/> instance that can be used to create tasks for several
43 /// purposes. For example, to create a <see cref="Task{TResult}"/> that runs a function, the factory's StartNew
44 /// method may be used:
47 /// var t = Task<int>.Factory.StartNew(() => GenerateResult());
49 /// var t = Task.Factory.StartNew(() => GenerateResult());
52 /// Dim t = Task<int>.Factory.StartNew(Function() GenerateResult())
54 /// Dim t = Task.Factory.StartNew(Function() GenerateResult())
58 /// The <see cref="Task{TResult}"/> class also provides constructors that initialize the task but that do not
59 /// schedule it for execution. For performance reasons, the StartNew method should be the
60 /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation
61 /// and scheduling must be separated, the constructors may be used, and the task's
62 /// <see cref="System.Threading.Tasks.Task.Start()">Start</see>
63 /// method may then be used to schedule the task for execution at a later time.
66 /// All members of <see cref="Task{TResult}"/>, except for
67 /// <see cref="System.Threading.Tasks.Task.Dispose()">Dispose</see>, are thread-safe
68 /// and may be used from multiple threads concurrently.
71 [HostProtection(Synchronization = true, ExternalThreading = true)]
72 [DebuggerTypeProxy(typeof(SystemThreadingTasks_FutureDebugView<>))]
73 [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")]
74 public class Task<TResult> : Task
75 #if SUPPORT_IOBSERVABLE
76 , IObservable<TResult>
79 internal TResult m_result; // The value itself, if set.
81 private static readonly TaskFactory<TResult> s_Factory = new TaskFactory<TResult>();
84 // public static Task<Task<TResult>> WhenAny<TResult>(IEnumerable<Task<TResult>> tasks);
85 // public static Task<Task<TResult>> WhenAny<TResult>(params Task<TResult>[] tasks);
86 // Used to "cast" from Task<Task> to Task<Task<TResult>>.
87 internal static readonly Func<Task<Task>, Task<TResult>> TaskWhenAnyCast = completed => (Task<TResult>)completed.Result;
89 // Construct a promise-style task without any options.
95 // Construct a promise-style task with state and options.
96 internal Task(object state, TaskCreationOptions options) :
97 base(state, options, promiseStyle:true)
102 // Construct a pre-completed Task<TResult>
103 internal Task(TResult result) :
104 base(false, TaskCreationOptions.None, default(CancellationToken))
109 internal Task(bool canceled, TResult result, TaskCreationOptions creationOptions, CancellationToken ct)
110 : base(canceled, creationOptions, ct)
118 // Uncomment if/when we want Task.FromException
119 //// Construct a pre-faulted Task<TResult>
120 //internal Task(Exception exception)
126 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
128 /// <param name="function">
129 /// The delegate that represents the code to execute in the task. When the function has completed,
130 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
132 /// <exception cref="T:System.ArgumentException">
133 /// The <paramref name="function"/> argument is null.
135 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
136 public Task(Func<TResult> function)
137 : this(function, null, default(CancellationToken),
138 TaskCreationOptions.None, InternalTaskOptions.None, null)
140 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
141 PossiblyCaptureContext(ref stackMark);
146 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
148 /// <param name="function">
149 /// The delegate that represents the code to execute in the task. When the function has completed,
150 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
152 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to this task.</param>
153 /// <exception cref="T:System.ArgumentException">
154 /// The <paramref name="function"/> argument is null.
156 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
157 /// has already been disposed.
159 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
160 public Task(Func<TResult> function, CancellationToken cancellationToken)
161 : this(function, null, cancellationToken,
162 TaskCreationOptions.None, InternalTaskOptions.None, null)
164 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
165 PossiblyCaptureContext(ref stackMark);
169 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
171 /// <param name="function">
172 /// The delegate that represents the code to execute in the task. When the function has completed,
173 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
175 /// <param name="creationOptions">
176 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
177 /// customize the task's behavior.
179 /// <exception cref="T:System.ArgumentException">
180 /// The <paramref name="function"/> argument is null.
182 /// <exception cref="T:System.ArgumentOutOfRangeException">
183 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
184 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
186 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
187 public Task(Func<TResult> function, TaskCreationOptions creationOptions)
188 : this(function, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
190 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
191 PossiblyCaptureContext(ref stackMark);
195 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
197 /// <param name="function">
198 /// The delegate that represents the code to execute in the task. When the function has completed,
199 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
201 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
202 /// <param name="creationOptions">
203 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
204 /// customize the task's behavior.
206 /// <exception cref="T:System.ArgumentException">
207 /// The <paramref name="function"/> argument is null.
209 /// <exception cref="T:System.ArgumentOutOfRangeException">
210 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
211 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
213 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
214 /// has already been disposed.
216 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
217 public Task(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
218 : this(function, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
220 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
221 PossiblyCaptureContext(ref stackMark);
225 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and state.
227 /// <param name="function">
228 /// The delegate that represents the code to execute in the task. When the function has completed,
229 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
231 /// <param name="state">An object representing data to be used by the action.</param>
232 /// <exception cref="T:System.ArgumentException">
233 /// The <paramref name="function"/> argument is null.
235 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
236 public Task(Func<object, TResult> function, object state)
237 : this(function, state, null, default(CancellationToken),
238 TaskCreationOptions.None, InternalTaskOptions.None, null)
240 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
241 PossiblyCaptureContext(ref stackMark);
245 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
247 /// <param name="function">
248 /// The delegate that represents the code to execute in the task. When the function has completed,
249 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
251 /// <param name="state">An object representing data to be used by the function.</param>
252 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</param>
253 /// <exception cref="T:System.ArgumentException">
254 /// The <paramref name="function"/> argument is null.
256 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
257 /// has already been disposed.
259 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
260 public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken)
261 : this(function, state, null, cancellationToken,
262 TaskCreationOptions.None, InternalTaskOptions.None, null)
264 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
265 PossiblyCaptureContext(ref stackMark);
269 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
271 /// <param name="function">
272 /// The delegate that represents the code to execute in the task. When the function has completed,
273 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
275 /// <param name="state">An object representing data to be used by the function.</param>
276 /// <param name="creationOptions">
277 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
278 /// customize the task's behavior.
280 /// <exception cref="T:System.ArgumentException">
281 /// The <paramref name="function"/> argument is null.
283 /// <exception cref="T:System.ArgumentOutOfRangeException">
284 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
285 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
287 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
288 public Task(Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
289 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken),
290 creationOptions, InternalTaskOptions.None, null)
292 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
293 PossiblyCaptureContext(ref stackMark);
298 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
300 /// <param name="function">
301 /// The delegate that represents the code to execute in the task. When the function has completed,
302 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
304 /// <param name="state">An object representing data to be used by the function.</param>
305 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</param>
306 /// <param name="creationOptions">
307 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
308 /// customize the task's behavior.
310 /// <exception cref="T:System.ArgumentException">
311 /// The <paramref name="function"/> argument is null.
313 /// <exception cref="T:System.ArgumentOutOfRangeException">
314 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
315 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
317 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
318 /// has already been disposed.
320 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
321 public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
322 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken,
323 creationOptions, InternalTaskOptions.None, null)
325 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
326 PossiblyCaptureContext(ref stackMark);
330 Func<TResult> valueSelector, Task parent, CancellationToken cancellationToken,
331 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler,
332 ref StackCrawlMark stackMark) :
333 this(valueSelector, parent, cancellationToken,
334 creationOptions, internalOptions, scheduler)
336 PossiblyCaptureContext(ref stackMark);
340 /// Creates a new future object.
342 /// <param name="parent">The parent task for this future.</param>
343 /// <param name="valueSelector">A function that yields the future value.</param>
344 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
345 /// <param name="cancellationToken">The CancellationToken for the task.</param>
346 /// <param name="creationOptions">Options to control the future's behavior.</param>
347 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
348 /// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="creationOptions"/> argument specifies
349 /// a SelfReplicating <see cref="Task{TResult}"/>, which is illegal."/>.</exception>
350 internal Task(Func<TResult> valueSelector, Task parent, CancellationToken cancellationToken,
351 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
352 base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler)
354 if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
356 throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating"));
361 Func<object, TResult> valueSelector, object state, Task parent, CancellationToken cancellationToken,
362 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) :
363 this(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
365 PossiblyCaptureContext(ref stackMark);
369 /// Creates a new future object.
371 /// <param name="parent">The parent task for this future.</param>
372 /// <param name="state">An object containing data to be used by the action; may be null.</param>
373 /// <param name="valueSelector">A function that yields the future value.</param>
374 /// <param name="cancellationToken">The CancellationToken for the task.</param>
375 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
376 /// <param name="creationOptions">Options to control the future's behavior.</param>
377 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
378 /// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="creationOptions"/> argument specifies
379 /// a SelfReplicating <see cref="Task{TResult}"/>, which is illegal."/>.</exception>
380 internal Task(Delegate valueSelector, object state, Task parent, CancellationToken cancellationToken,
381 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
382 base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
384 if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
386 throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating"));
391 // Internal method used by TaskFactory<TResult>.StartNew() methods
392 internal static Task<TResult> StartNew(Task parent, Func<TResult> function, CancellationToken cancellationToken,
393 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
395 if (function == null)
397 throw new ArgumentNullException("function");
399 if (scheduler == null)
401 throw new ArgumentNullException("scheduler");
403 if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
406 throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating"));
409 // Create and schedule the future.
410 Task<TResult> f = new Task<TResult>(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark);
412 f.ScheduleAndStart(false);
416 // Internal method used by TaskFactory<TResult>.StartNew() methods
417 internal static Task<TResult> StartNew(Task parent, Func<object, TResult> function, object state, CancellationToken cancellationToken,
418 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
420 if (function == null)
422 throw new ArgumentNullException("function");
424 if (scheduler == null)
426 throw new ArgumentNullException("scheduler");
428 if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
430 throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating"));
433 // Create and schedule the future.
434 Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark);
436 f.ScheduleAndStart(false);
441 private string DebuggerDisplayResultDescription
445 return IsRanToCompletion ? "" + m_result : Environment.GetResourceString("TaskT_DebuggerNoResult");
450 private string DebuggerDisplayMethodDescription
454 Delegate d = (Delegate)m_action;
455 return d != null ? d.Method.ToString() : "{null}";
460 // internal helper function breaks out logic used by TaskCompletionSource
461 internal bool TrySetResult(TResult result)
463 if (IsCompleted) return false;
464 Contract.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action");
466 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
467 // has been made, (2) The result has not already been set, (3) An exception has not previously
468 // been recorded, and (4) Cancellation has not been requested.
470 // If the reservation is successful, then set the result and finish completion processing.
471 if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED,
472 TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
476 // Signal completion, for waiting tasks
478 // This logic used to be:
480 // However, that goes through a windy code path, involves many non-inlineable functions
481 // and which can be summarized more concisely with the following snippet from
482 // FinishStageTwo, omitting everything that doesn't pertain to TrySetResult.
483 Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION);
485 var cp = m_contingentProperties;
486 if (cp != null) cp.SetCompleted();
496 // Transitions the promise task into a successfully completed state with the specified result.
497 // This is dangerous, as no synchronization is used, and thus must only be used
498 // before this task is handed out to any consumers, before any continuations are hooked up,
499 // before its wait handle is accessed, etc. It's use is limited to places like in FromAsync
500 // where the operation completes synchronously, and thus we know we can forcefully complete
501 // the task, avoiding expensive completion paths, before the task is actually given to anyone.
502 internal void DangerousSetResult(TResult result)
504 Contract.Assert(!IsCompleted, "The promise must not yet be completed.");
506 // If we have a parent, we need to notify it of the completion. Take the slow path to handle that.
507 if (m_parent != null)
509 bool success = TrySetResult(result);
511 // Nobody else has had a chance to complete this Task yet, so we should succeed.
512 Contract.Assert(success);
517 m_stateFlags |= TASK_STATE_RAN_TO_COMPLETION;
522 /// Gets the result value of this <see cref="Task{TResult}"/>.
525 /// The get accessor for this property ensures that the asynchronous operation is complete before
526 /// returning. Once the result of the computation is available, it is stored and will be returned
527 /// immediately on later calls to <see cref="Result"/>.
529 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
530 public TResult Result
533 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
535 get { return IsWaitNotificationEnabledOrNotRanToCompletion ? GetResultCore(waitCompletionNotification: true) : m_result; }
539 /// Gets the result value of this <see cref="Task{TResult}"/> once the task has completed successfully.
542 /// This version of Result should only be used if the task completed successfully and if there's
543 /// no debugger wait notification enabled for this task.
545 internal TResult ResultOnSuccess
548 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
552 Contract.Assert(!IsWaitNotificationEnabledOrNotRanToCompletion,
553 "Should only be used when the task completed successfully and there's no wait notification enabled");
558 // Implements Result. Result delegates to this method if the result isn't already available.
559 internal TResult GetResultCore(bool waitCompletionNotification)
561 // If the result has not been calculated yet, wait for it.
562 if (!IsCompleted) InternalWait(Timeout.Infinite, default(CancellationToken)); // won't throw if task faulted or canceled; that's handled below
564 // Notify the debugger of the wait completion if it's requested such a notification
565 if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary();
567 // Throw an exception if appropriate.
568 if (!IsRanToCompletion) ThrowIfExceptional(includeTaskCanceledExceptions: true);
570 // We shouldn't be here if the result has not been set.
571 Contract.Assert(IsRanToCompletion, "Task<T>.Result getter: Expected result to have been set.");
576 // Allow multiple exceptions to be assigned to a promise-style task.
577 // This is useful when a TaskCompletionSource<T> stands in as a proxy
578 // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll())
579 // and the "real" task ends up with multiple exceptions, which is possible when
580 // a task has children.
582 // Called from TaskCompletionSource<T>.SetException(IEnumerable<Exception>).
583 internal bool TrySetException(object exceptionObject)
585 Contract.Assert(m_action == null, "Task<T>.TrySetException(): non-null m_action");
587 // TCS.{Try}SetException() should have checked for this
588 Contract.Assert(exceptionObject != null, "Expected non-null exceptionObject argument");
590 // Only accept these types.
592 (exceptionObject is Exception) || (exceptionObject is IEnumerable<Exception>) ||
593 (exceptionObject is ExceptionDispatchInfo) || (exceptionObject is IEnumerable<ExceptionDispatchInfo>),
594 "Expected exceptionObject to be either Exception, ExceptionDispatchInfo, or IEnumerable<> of one of those");
596 bool returnValue = false;
598 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
599 // has been made, (2) The result has not already been set, (3) An exception has not previously
600 // been recorded, and (4) Cancellation has not been requested.
602 // If the reservation is successful, then add the exception(s) and finish completion processing.
604 // The lazy initialization may not be strictly necessary, but I'd like to keep it here
605 // anyway. Some downstream logic may depend upon an inflated m_contingentProperties.
606 EnsureContingentPropertiesInitialized(needsProtection: true);
607 if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED,
608 TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
610 AddException(exceptionObject); // handles singleton exception or exception collection
619 // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder
620 // If the tokenToRecord is not None, it will be stored onto the task.
621 // This method is only valid for promise tasks.
622 internal bool TrySetCanceled(CancellationToken tokenToRecord)
624 return TrySetCanceled(tokenToRecord, null);
627 // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder
628 // If the tokenToRecord is not None, it will be stored onto the task.
629 // If the OperationCanceledException is not null, it will be stored into the task's exception holder.
630 // This method is only valid for promise tasks.
631 internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException)
633 Contract.Assert(m_action == null, "Task<T>.TrySetCanceled(): non-null m_action");
635 var ceAsEdi = cancellationException as ExceptionDispatchInfo;
637 cancellationException == null ||
638 cancellationException is OperationCanceledException ||
639 (ceAsEdi != null && ceAsEdi.SourceException is OperationCanceledException),
640 "Expected null or an OperationCanceledException");
643 bool returnValue = false;
645 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
646 // has been made, (2) The result has not already been set, (3) An exception has not previously
647 // been recorded, and (4) Cancellation has not been requested.
649 // If the reservation is successful, then record the cancellation and finish completion processing.
651 // Note: I had to access static Task variables through Task<object>
652 // instead of Task, because I have a property named Task and that
653 // was confusing the compiler.
654 if (AtomicStateUpdate(Task<object>.TASK_STATE_COMPLETION_RESERVED,
655 Task<object>.TASK_STATE_COMPLETION_RESERVED | Task<object>.TASK_STATE_CANCELED |
656 Task<object>.TASK_STATE_FAULTED | Task<object>.TASK_STATE_RAN_TO_COMPLETION))
658 RecordInternalCancellationRequest(tokenToRecord, cancellationException);
659 CancellationCleanupLogic(); // perform cancellation cleanup actions
667 /// Provides access to factory methods for creating <see cref="Task{TResult}"/> instances.
670 /// The factory returned from <see cref="Factory"/> is a default instance
671 /// of <see cref="System.Threading.Tasks.TaskFactory{TResult}"/>, as would result from using
672 /// the default constructor on the factory type.
674 public new static TaskFactory<TResult> Factory { get { return s_Factory; } }
677 /// Evaluates the value selector of the Task which is passed in as an object and stores the result.
679 internal override void InnerInvoke()
681 // Invoke the delegate
682 Contract.Assert(m_action != null);
683 var func = m_action as Func<TResult>;
689 var funcWithState = m_action as Func<object, TResult>;
690 if (funcWithState != null)
692 m_result = funcWithState(m_stateObject);
695 Contract.Assert(false, "Invalid m_action in Task<TResult>");
698 #if !FEATURE_CORECLR || FEATURE_NETCORE
699 #region Await Support
701 /// <summary>Gets an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
702 /// <returns>An awaiter instance.</returns>
703 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
705 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
707 public new TaskAwaiter<TResult> GetAwaiter()
709 return new TaskAwaiter<TResult>(this);
712 /// <summary>Configures an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
713 /// <param name="continueOnCapturedContext">
714 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
716 /// <returns>An object used to await this task.</returns>
718 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
720 public new ConfiguredTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
722 return new ConfiguredTaskAwaitable<TResult>(this, continueOnCapturedContext);
727 #region Continuation methods
729 #region Action<Task<TResult>> continuations
732 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
734 /// <param name="continuationAction">
735 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
736 /// passed the completed task as an argument.
738 /// <returns>A new continuation <see cref="Task"/>.</returns>
740 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
741 /// completed, whether it completes due to running to completion successfully, faulting due to an
742 /// unhandled exception, or exiting out early due to being canceled.
744 /// <exception cref="T:System.ArgumentNullException">
745 /// The <paramref name="continuationAction"/> argument is null.
747 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
748 public Task ContinueWith(Action<Task<TResult>> continuationAction)
750 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
751 return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
756 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
758 /// <param name="continuationAction">
759 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
760 /// passed the completed task as an argument.
762 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
763 /// <returns>A new continuation <see cref="Task"/>.</returns>
765 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
766 /// completed, whether it completes due to running to completion successfully, faulting due to an
767 /// unhandled exception, or exiting out early due to being canceled.
769 /// <exception cref="T:System.ArgumentNullException">
770 /// The <paramref name="continuationAction"/> argument is null.
772 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
773 /// has already been disposed.
775 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
776 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken)
778 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
779 return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
784 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
786 /// <param name="continuationAction">
787 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
788 /// passed the completed task as an argument.
790 /// <param name="scheduler">
791 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
793 /// <returns>A new continuation <see cref="Task"/>.</returns>
795 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
796 /// completed, whether it completes due to running to completion successfully, faulting due to an
797 /// unhandled exception, or exiting out early due to being canceled.
799 /// <exception cref="T:System.ArgumentNullException">
800 /// The <paramref name="continuationAction"/> argument is null.
802 /// <exception cref="T:System.ArgumentNullException">
803 /// The <paramref name="scheduler"/> argument is null.
805 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
806 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler)
808 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
809 return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
813 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
815 /// <param name="continuationAction">
816 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
817 /// passed the completed task as an argument.
819 /// <param name="continuationOptions">
820 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
822 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
823 /// well as execution options, such as <see
824 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
826 /// <returns>A new continuation <see cref="Task"/>.</returns>
828 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
829 /// completed. If the continuation criteria specified through the <paramref
830 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
831 /// instead of scheduled.
833 /// <exception cref="T:System.ArgumentNullException">
834 /// The <paramref name="continuationAction"/> argument is null.
836 /// <exception cref="T:System.ArgumentOutOfRangeException">
837 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
838 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
840 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
841 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskContinuationOptions continuationOptions)
843 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
844 return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
848 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
850 /// <param name="continuationAction">
851 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
852 /// passed the completed task as an argument.
854 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
855 /// <param name="continuationOptions">
856 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
858 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
859 /// well as execution options, such as <see
860 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
862 /// <param name="scheduler">
863 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
866 /// <returns>A new continuation <see cref="Task"/>.</returns>
868 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
869 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
870 /// are not met, the continuation task will be canceled instead of scheduled.
872 /// <exception cref="T:System.ArgumentNullException">
873 /// The <paramref name="continuationAction"/> argument is null.
875 /// <exception cref="T:System.ArgumentOutOfRangeException">
876 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
877 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
879 /// <exception cref="T:System.ArgumentNullException">
880 /// The <paramref name="scheduler"/> argument is null.
882 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
883 /// has already been disposed.
885 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
886 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken,
887 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
889 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
890 return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
893 // Same as the above overload, only with a stack mark.
894 internal Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken,
895 TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
897 if (continuationAction == null)
899 throw new ArgumentNullException("continuationAction");
902 if (scheduler == null)
904 throw new ArgumentNullException("scheduler");
907 TaskCreationOptions creationOptions;
908 InternalTaskOptions internalOptions;
909 CreationOptionsFromContinuationOptions(
912 out internalOptions);
914 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
915 this, continuationAction, null,
916 creationOptions, internalOptions,
920 // Register the continuation. If synchronous execution is requested, this may
921 // actually invoke the continuation before returning.
922 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
924 return continuationTask;
928 #region Action<Task<TResult>, Object> continuations
931 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
933 /// <param name="continuationAction">
934 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
935 /// passed the completed task and the caller-supplied state object as arguments.
937 /// <param name="state">An object representing data to be used by the continuation action.</param>
938 /// <returns>A new continuation <see cref="Task"/>.</returns>
940 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
941 /// completed, whether it completes due to running to completion successfully, faulting due to an
942 /// unhandled exception, or exiting out early due to being canceled.
944 /// <exception cref="T:System.ArgumentNullException">
945 /// The <paramref name="continuationAction"/> argument is null.
947 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
948 public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state)
950 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
951 return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
956 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
958 /// <param name="continuationAction">
959 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
960 /// passed the completed task and the caller-supplied state object as arguments.
962 /// <param name="state">An object representing data to be used by the continuation action.</param>
963 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
964 /// <returns>A new continuation <see cref="Task"/>.</returns>
966 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
967 /// completed, whether it completes due to running to completion successfully, faulting due to an
968 /// unhandled exception, or exiting out early due to being canceled.
970 /// <exception cref="T:System.ArgumentNullException">
971 /// The <paramref name="continuationAction"/> argument is null.
973 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
974 /// has already been disposed.
976 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
977 public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,CancellationToken cancellationToken)
979 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
980 return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
985 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
987 /// <param name="continuationAction">
988 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
989 /// passed the completed task and the caller-supplied state object as arguments.
991 /// <param name="state">An object representing data to be used by the continuation action.</param>
992 /// <param name="scheduler">
993 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
995 /// <returns>A new continuation <see cref="Task"/>.</returns>
997 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
998 /// completed, whether it completes due to running to completion successfully, faulting due to an
999 /// unhandled exception, or exiting out early due to being canceled.
1001 /// <exception cref="T:System.ArgumentNullException">
1002 /// The <paramref name="continuationAction"/> argument is null.
1004 /// <exception cref="T:System.ArgumentNullException">
1005 /// The <paramref name="scheduler"/> argument is null.
1007 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1008 public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, TaskScheduler scheduler)
1010 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1011 return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
1015 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1017 /// <param name="continuationAction">
1018 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1019 /// passed the completed task and the caller-supplied state object as arguments.
1021 /// <param name="state">An object representing data to be used by the continuation action.</param>
1022 /// <param name="continuationOptions">
1023 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1025 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1026 /// well as execution options, such as <see
1027 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1029 /// <returns>A new continuation <see cref="Task"/>.</returns>
1031 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
1032 /// completed. If the continuation criteria specified through the <paramref
1033 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
1034 /// instead of scheduled.
1036 /// <exception cref="T:System.ArgumentNullException">
1037 /// The <paramref name="continuationAction"/> argument is null.
1039 /// <exception cref="T:System.ArgumentOutOfRangeException">
1040 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1041 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1043 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1044 public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,TaskContinuationOptions continuationOptions)
1046 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1047 return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
1051 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1053 /// <param name="continuationAction">
1054 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1055 /// passed the completed task and the caller-supplied state object as arguments.
1057 /// <param name="state">An object representing data to be used by the continuation action.</param>
1058 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
1059 /// <param name="continuationOptions">
1060 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1062 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1063 /// well as execution options, such as <see
1064 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1066 /// <param name="scheduler">
1067 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1070 /// <returns>A new continuation <see cref="Task"/>.</returns>
1072 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
1073 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
1074 /// are not met, the continuation task will be canceled instead of scheduled.
1076 /// <exception cref="T:System.ArgumentNullException">
1077 /// The <paramref name="continuationAction"/> argument is null.
1079 /// <exception cref="T:System.ArgumentOutOfRangeException">
1080 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1081 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1083 /// <exception cref="T:System.ArgumentNullException">
1084 /// The <paramref name="scheduler"/> argument is null.
1086 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1087 /// has already been disposed.
1089 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1090 public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, CancellationToken cancellationToken,
1091 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1093 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1094 return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
1097 // Same as the above overload, only with a stack mark.
1098 internal Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken,
1099 TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
1101 if (continuationAction == null)
1103 throw new ArgumentNullException("continuationAction");
1106 if (scheduler == null)
1108 throw new ArgumentNullException("scheduler");
1111 TaskCreationOptions creationOptions;
1112 InternalTaskOptions internalOptions;
1113 CreationOptionsFromContinuationOptions(
1114 continuationOptions,
1115 out creationOptions,
1116 out internalOptions);
1118 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
1119 this, continuationAction, state,
1120 creationOptions, internalOptions,
1124 // Register the continuation. If synchronous execution is requested, this may
1125 // actually invoke the continuation before returning.
1126 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
1128 return continuationTask;
1133 #region Func<Task<TResult>,TNewResult> continuations
1136 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1138 /// <typeparam name="TNewResult">
1139 /// The type of the result produced by the continuation.
1141 /// <param name="continuationFunction">
1142 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1143 /// passed the completed task as an argument.
1145 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1147 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1148 /// task has completed, whether it completes due to running to completion successfully, faulting due
1149 /// to an unhandled exception, or exiting out early due to being canceled.
1151 /// <exception cref="T:System.ArgumentNullException">
1152 /// The <paramref name="continuationFunction"/> argument is null.
1154 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1155 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction)
1157 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1158 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
1163 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1165 /// <typeparam name="TNewResult">
1166 /// The type of the result produced by the continuation.
1168 /// <param name="continuationFunction">
1169 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1170 /// passed the completed task as an argument.
1172 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1173 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1175 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1176 /// task has completed, whether it completes due to running to completion successfully, faulting due
1177 /// to an unhandled exception, or exiting out early due to being canceled.
1179 /// <exception cref="T:System.ArgumentNullException">
1180 /// The <paramref name="continuationFunction"/> argument is null.
1182 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1183 /// has already been disposed.
1185 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1186 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken)
1188 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1189 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
1193 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1195 /// <typeparam name="TNewResult">
1196 /// The type of the result produced by the continuation.
1198 /// <param name="continuationFunction">
1199 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1200 /// passed the completed task as an argument.
1202 /// <param name="scheduler">
1203 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
1205 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1207 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1208 /// completed, whether it completes due to running to completion successfully, faulting due to an
1209 /// unhandled exception, or exiting out early due to being canceled.
1211 /// <exception cref="T:System.ArgumentNullException">
1212 /// The <paramref name="continuationFunction"/> argument is null.
1214 /// <exception cref="T:System.ArgumentNullException">
1215 /// The <paramref name="scheduler"/> argument is null.
1217 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1218 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler)
1220 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1221 return ContinueWith<TNewResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
1225 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1227 /// <typeparam name="TNewResult">
1228 /// The type of the result produced by the continuation.
1230 /// <param name="continuationFunction">
1231 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1232 /// passed the completed task as an argument.
1234 /// <param name="continuationOptions">
1235 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1237 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1238 /// well as execution options, such as <see
1239 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1241 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1244 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1245 /// task has completed, whether it completes due to running to completion successfully, faulting due
1246 /// to an unhandled exception, or exiting out early due to being canceled.
1249 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1250 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1251 /// from the ContinueWith call.
1254 /// <exception cref="T:System.ArgumentNullException">
1255 /// The <paramref name="continuationFunction"/> argument is null.
1257 /// <exception cref="T:System.ArgumentOutOfRangeException">
1258 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1259 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1261 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1262 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions)
1264 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1265 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
1269 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1271 /// <typeparam name="TNewResult">
1272 /// The type of the result produced by the continuation.
1274 /// <param name="continuationFunction">
1275 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be passed as
1276 /// an argument this completed task.
1278 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1279 /// <param name="continuationOptions">
1280 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1282 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1283 /// well as execution options, such as <see
1284 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1286 /// <param name="scheduler">
1287 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1290 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1293 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1294 /// completed, whether it completes due to running to completion successfully, faulting due to an
1295 /// unhandled exception, or exiting out early due to being canceled.
1298 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1299 /// This task's completion state will be transferred to the task returned from the
1300 /// ContinueWith call.
1303 /// <exception cref="T:System.ArgumentNullException">
1304 /// The <paramref name="continuationFunction"/> argument is null.
1306 /// <exception cref="T:System.ArgumentOutOfRangeException">
1307 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1308 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1310 /// <exception cref="T:System.ArgumentNullException">
1311 /// The <paramref name="scheduler"/> argument is null.
1313 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1314 /// has already been disposed.
1316 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1317 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken,
1318 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1320 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1321 return ContinueWith<TNewResult>(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
1324 // Same as the above overload, just with a stack mark.
1325 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler,
1326 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
1328 if (continuationFunction == null)
1330 throw new ArgumentNullException("continuationFunction");
1333 if (scheduler == null)
1335 throw new ArgumentNullException("scheduler");
1338 TaskCreationOptions creationOptions;
1339 InternalTaskOptions internalOptions;
1340 CreationOptionsFromContinuationOptions(
1341 continuationOptions,
1342 out creationOptions,
1343 out internalOptions);
1345 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
1346 this, continuationFunction, null,
1347 creationOptions, internalOptions,
1351 // Register the continuation. If synchronous execution is requested, this may
1352 // actually invoke the continuation before returning.
1353 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1355 return continuationFuture;
1359 #region Func<Task<TResult>, Object,TNewResult> continuations
1362 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1364 /// <typeparam name="TNewResult">
1365 /// The type of the result produced by the continuation.
1367 /// <param name="continuationFunction">
1368 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1369 /// passed the completed task and the caller-supplied state object as arguments.
1371 /// <param name="state">An object representing data to be used by the continuation function.</param>
1372 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1374 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1375 /// task has completed, whether it completes due to running to completion successfully, faulting due
1376 /// to an unhandled exception, or exiting out early due to being canceled.
1378 /// <exception cref="T:System.ArgumentNullException">
1379 /// The <paramref name="continuationFunction"/> argument is null.
1381 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1382 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state)
1384 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1385 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
1390 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1392 /// <typeparam name="TNewResult">
1393 /// The type of the result produced by the continuation.
1395 /// <param name="continuationFunction">
1396 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1397 /// passed the completed task and the caller-supplied state object as arguments.
1399 /// <param name="state">An object representing data to be used by the continuation function.</param>
1400 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1401 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1403 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1404 /// task has completed, whether it completes due to running to completion successfully, faulting due
1405 /// to an unhandled exception, or exiting out early due to being canceled.
1407 /// <exception cref="T:System.ArgumentNullException">
1408 /// The <paramref name="continuationFunction"/> argument is null.
1410 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1411 /// has already been disposed.
1413 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1414 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
1415 CancellationToken cancellationToken)
1417 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1418 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
1422 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1424 /// <typeparam name="TNewResult">
1425 /// The type of the result produced by the continuation.
1427 /// <param name="continuationFunction">
1428 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1429 /// passed the completed task and the caller-supplied state object as arguments.
1431 /// <param name="state">An object representing data to be used by the continuation function.</param>
1432 /// <param name="scheduler">
1433 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
1435 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1437 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1438 /// completed, whether it completes due to running to completion successfully, faulting due to an
1439 /// unhandled exception, or exiting out early due to being canceled.
1441 /// <exception cref="T:System.ArgumentNullException">
1442 /// The <paramref name="continuationFunction"/> argument is null.
1444 /// <exception cref="T:System.ArgumentNullException">
1445 /// The <paramref name="scheduler"/> argument is null.
1447 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1448 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
1449 TaskScheduler scheduler)
1451 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1452 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
1456 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1458 /// <typeparam name="TNewResult">
1459 /// The type of the result produced by the continuation.
1461 /// <param name="continuationFunction">
1462 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1463 /// passed the completed task and the caller-supplied state object as arguments.
1465 /// <param name="state">An object representing data to be used by the continuation function.</param>
1466 /// <param name="continuationOptions">
1467 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1469 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1470 /// well as execution options, such as <see
1471 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1473 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1476 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1477 /// task has completed, whether it completes due to running to completion successfully, faulting due
1478 /// to an unhandled exception, or exiting out early due to being canceled.
1481 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1482 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1483 /// from the ContinueWith call.
1486 /// <exception cref="T:System.ArgumentNullException">
1487 /// The <paramref name="continuationFunction"/> argument is null.
1489 /// <exception cref="T:System.ArgumentOutOfRangeException">
1490 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1491 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1493 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1494 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
1495 TaskContinuationOptions continuationOptions)
1497 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1498 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
1502 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1504 /// <typeparam name="TNewResult">
1505 /// The type of the result produced by the continuation.
1507 /// <param name="continuationFunction">
1508 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1509 /// passed the completed task and the caller-supplied state object as arguments.
1511 /// <param name="state">An object representing data to be used by the continuation function.</param>
1512 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1513 /// <param name="continuationOptions">
1514 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1516 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1517 /// well as execution options, such as <see
1518 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1520 /// <param name="scheduler">
1521 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1524 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1527 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1528 /// completed, whether it completes due to running to completion successfully, faulting due to an
1529 /// unhandled exception, or exiting out early due to being canceled.
1532 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1533 /// This task's completion state will be transferred to the task returned from the
1534 /// ContinueWith call.
1537 /// <exception cref="T:System.ArgumentNullException">
1538 /// The <paramref name="continuationFunction"/> argument is null.
1540 /// <exception cref="T:System.ArgumentOutOfRangeException">
1541 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1542 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1544 /// <exception cref="T:System.ArgumentNullException">
1545 /// The <paramref name="scheduler"/> argument is null.
1547 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1548 /// has already been disposed.
1550 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
1551 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
1552 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1554 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
1555 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
1558 // Same as the above overload, just with a stack mark.
1559 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
1560 TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
1562 if (continuationFunction == null)
1564 throw new ArgumentNullException("continuationFunction");
1567 if (scheduler == null)
1569 throw new ArgumentNullException("scheduler");
1572 TaskCreationOptions creationOptions;
1573 InternalTaskOptions internalOptions;
1574 CreationOptionsFromContinuationOptions(
1575 continuationOptions,
1576 out creationOptions,
1577 out internalOptions);
1579 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
1580 this, continuationFunction, state,
1581 creationOptions, internalOptions,
1585 // Register the continuation. If synchronous execution is requested, this may
1586 // actually invoke the continuation before returning.
1587 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1589 return continuationFuture;
1597 /// Subscribes an <see cref="IObserver{TResult}"/> to receive notification of the final state of this <see cref="Task{TResult}"/>.
1599 /// <param name="observer">
1600 /// The <see cref="IObserver{TResult}"/> to call on task completion. If this Task throws an exception,
1601 /// observer.OnError is called with this Task's AggregateException. If this Task RanToCompletion,
1602 /// observer.OnNext is called with this Task's result, followed by a call to observer.OnCompleted.
1603 /// If this Task is Canceled, observer.OnError is called with a TaskCanceledException
1604 /// containing this Task's CancellationToken
1606 /// <returns>An IDisposable object <see cref="Task"/>.</returns>
1607 /// <exception cref="T:System.ArgumentNullException">
1608 /// The <paramref name="observer"/> argument is null.
1610 #if SUPPORT_IOBSERVABLE
1611 IDisposable IObservable<TResult>.Subscribe(IObserver<TResult> observer)
1613 if (observer == null)
1614 throw new System.ArgumentNullException("observer");
1617 var continuationTask =
1618 this.ContinueWith(delegate(Task<TResult> observedTask, object taskObserverObject)
1620 IObserver<TResult> taskObserver = (IObserver<TResult>)taskObserverObject;
1621 if (observedTask.IsFaulted)
1622 taskObserver.OnError(observedTask.Exception);
1623 else if (observedTask.IsCanceled)
1624 taskObserver.OnError(new TaskCanceledException(observedTask));
1627 taskObserver.OnNext(observedTask.Result);
1628 taskObserver.OnCompleted();
1631 }, observer, TaskScheduler.Default);
1633 return new DisposableSubscription(this, continuationTask);
1638 #if SUPPORT_IOBSERVABLE
1639 // Class that calls RemoveContinuation if Dispose() is called before task completion
1640 internal class DisposableSubscription : IDisposable
1642 private Task _notifyObserverContinuationTask;
1643 private Task _observedTask;
1645 internal DisposableSubscription(Task observedTask, Task notifyObserverContinuationTask)
1647 _observedTask = observedTask;
1648 _notifyObserverContinuationTask = notifyObserverContinuationTask;
1650 void IDisposable.Dispose()
1652 Task localObservedTask = _observedTask;
1653 Task localNotifyingContinuationTask = _notifyObserverContinuationTask;
1654 if (localObservedTask != null && localNotifyingContinuationTask != null && !localObservedTask.IsCompleted)
1656 localObservedTask.RemoveContinuation(localNotifyingContinuationTask);
1658 _observedTask = null;
1659 _notifyObserverContinuationTask = null;
1664 // Proxy class for better debugging experience
1665 internal class SystemThreadingTasks_FutureDebugView<TResult>
1667 private Task<TResult> m_task;
1669 public SystemThreadingTasks_FutureDebugView(Task<TResult> task)
1674 public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default(TResult); } }
1675 public object AsyncState { get { return m_task.AsyncState; } }
1676 public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } }
1677 public Exception Exception { get { return m_task.Exception; } }
1678 public int Id { get { return m_task.Id; } }
1679 public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } }
1680 public TaskStatus Status { get { return m_task.Status; } }