1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
9 // A task that produces a value.
11 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
14 using System.Collections.Generic;
16 using System.Runtime.CompilerServices;
17 using System.Runtime.ExceptionServices;
18 using System.Security;
19 using System.Threading;
20 using System.Diagnostics;
22 // Disable the "reference to volatile field not treated as volatile" error.
23 #pragma warning disable 0420
25 namespace System.Threading.Tasks
28 /// Represents an asynchronous operation that produces a result at some time in the future.
30 /// <typeparam name="TResult">
31 /// The type of the result produced by this <see cref="Task{TResult}"/>.
35 /// <see cref="Task{TResult}"/> instances may be created in a variety of ways. The most common approach is by
36 /// using the task's <see cref="Factory"/> property to retrieve a <see
37 /// cref="System.Threading.Tasks.TaskFactory{TResult}"/> instance that can be used to create tasks for several
38 /// purposes. For example, to create a <see cref="Task{TResult}"/> that runs a function, the factory's StartNew
39 /// method may be used:
42 /// var t = Task<int>.Factory.StartNew(() => GenerateResult());
44 /// var t = Task.Factory.StartNew(() => GenerateResult());
47 /// Dim t = Task<int>.Factory.StartNew(Function() GenerateResult())
49 /// Dim t = Task.Factory.StartNew(Function() GenerateResult())
53 /// The <see cref="Task{TResult}"/> class also provides constructors that initialize the task but that do not
54 /// schedule it for execution. For performance reasons, the StartNew method should be the
55 /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation
56 /// and scheduling must be separated, the constructors may be used, and the task's
57 /// <see cref="System.Threading.Tasks.Task.Start()">Start</see>
58 /// method may then be used to schedule the task for execution at a later time.
61 /// All members of <see cref="Task{TResult}"/>, except for
62 /// <see cref="System.Threading.Tasks.Task.Dispose()">Dispose</see>, are thread-safe
63 /// and may be used from multiple threads concurrently.
66 [DebuggerTypeProxy(typeof(SystemThreadingTasks_FutureDebugView<>))]
67 [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")]
68 public class Task<TResult> : Task
70 internal TResult m_result; // The value itself, if set.
72 private static readonly TaskFactory<TResult> s_Factory = new TaskFactory<TResult>();
75 // public static Task<Task<TResult>> WhenAny<TResult>(IEnumerable<Task<TResult>> tasks);
76 // public static Task<Task<TResult>> WhenAny<TResult>(params Task<TResult>[] tasks);
77 // Used to "cast" from Task<Task> to Task<Task<TResult>>.
78 internal static readonly Func<Task<Task>, Task<TResult>> TaskWhenAnyCast = completed => (Task<TResult>)completed.Result;
80 // Construct a promise-style task without any options.
86 // Construct a promise-style task with state and options.
87 internal Task(object state, TaskCreationOptions options) :
88 base(state, options, promiseStyle: true)
93 // Construct a pre-completed Task<TResult>
94 internal Task(TResult result) :
95 base(false, TaskCreationOptions.None, default)
100 internal Task(bool canceled, TResult result, TaskCreationOptions creationOptions, CancellationToken ct)
101 : base(canceled, creationOptions, ct)
109 // Uncomment if/when we want Task.FromException
110 //// Construct a pre-faulted Task<TResult>
111 //internal Task(Exception exception)
117 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
119 /// <param name="function">
120 /// The delegate that represents the code to execute in the task. When the function has completed,
121 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
123 /// <exception cref="T:System.ArgumentException">
124 /// The <paramref name="function"/> argument is null.
126 public Task(Func<TResult> function)
127 : this(function, null, default,
128 TaskCreationOptions.None, InternalTaskOptions.None, null)
134 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
136 /// <param name="function">
137 /// The delegate that represents the code to execute in the task. When the function has completed,
138 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
140 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to this task.</param>
141 /// <exception cref="T:System.ArgumentException">
142 /// The <paramref name="function"/> argument is null.
144 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
145 /// has already been disposed.
147 public Task(Func<TResult> function, CancellationToken cancellationToken)
148 : this(function, null, cancellationToken,
149 TaskCreationOptions.None, InternalTaskOptions.None, null)
154 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
156 /// <param name="function">
157 /// The delegate that represents the code to execute in the task. When the function has completed,
158 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
160 /// <param name="creationOptions">
161 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
162 /// customize the task's behavior.
164 /// <exception cref="T:System.ArgumentException">
165 /// The <paramref name="function"/> argument is null.
167 /// <exception cref="T:System.ArgumentOutOfRangeException">
168 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
169 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
171 public Task(Func<TResult> function, TaskCreationOptions creationOptions)
172 : this(function, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null)
177 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
179 /// <param name="function">
180 /// The delegate that represents the code to execute in the task. When the function has completed,
181 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
183 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
184 /// <param name="creationOptions">
185 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
186 /// customize the task's behavior.
188 /// <exception cref="T:System.ArgumentException">
189 /// The <paramref name="function"/> argument is null.
191 /// <exception cref="T:System.ArgumentOutOfRangeException">
192 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
193 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
195 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
196 /// has already been disposed.
198 public Task(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
199 : this(function, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
204 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and state.
206 /// <param name="function">
207 /// The delegate that represents the code to execute in the task. When the function has completed,
208 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
210 /// <param name="state">An object representing data to be used by the action.</param>
211 /// <exception cref="T:System.ArgumentException">
212 /// The <paramref name="function"/> argument is null.
214 public Task(Func<object, TResult> function, object state)
215 : this(function, state, null, default,
216 TaskCreationOptions.None, InternalTaskOptions.None, null)
221 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
223 /// <param name="function">
224 /// The delegate that represents the code to execute in the task. When the function has completed,
225 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
227 /// <param name="state">An object representing data to be used by the function.</param>
228 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</param>
229 /// <exception cref="T:System.ArgumentException">
230 /// The <paramref name="function"/> argument is null.
232 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
233 /// has already been disposed.
235 public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken)
236 : this(function, state, null, cancellationToken,
237 TaskCreationOptions.None, InternalTaskOptions.None, null)
242 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
244 /// <param name="function">
245 /// The delegate that represents the code to execute in the task. When the function has completed,
246 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
248 /// <param name="state">An object representing data to be used by the function.</param>
249 /// <param name="creationOptions">
250 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
251 /// customize the task's behavior.
253 /// <exception cref="T:System.ArgumentException">
254 /// The <paramref name="function"/> argument is null.
256 /// <exception cref="T:System.ArgumentOutOfRangeException">
257 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
258 /// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
260 public Task(Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
261 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default,
262 creationOptions, InternalTaskOptions.None, null)
268 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
270 /// <param name="function">
271 /// The delegate that represents the code to execute in the task. When the function has completed,
272 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
274 /// <param name="state">An object representing data to be used by the function.</param>
275 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</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 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
288 /// has already been disposed.
290 public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
291 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken,
292 creationOptions, InternalTaskOptions.None, null)
297 /// Creates a new future object.
299 /// <param name="parent">The parent task for this future.</param>
300 /// <param name="valueSelector">A function that yields the future value.</param>
301 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
302 /// <param name="cancellationToken">The CancellationToken for the task.</param>
303 /// <param name="creationOptions">Options to control the future's behavior.</param>
304 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
305 internal Task(Func<TResult> valueSelector, Task parent, CancellationToken cancellationToken,
306 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
307 base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler)
312 /// Creates a new future object.
314 /// <param name="parent">The parent task for this future.</param>
315 /// <param name="state">An object containing data to be used by the action; may be null.</param>
316 /// <param name="valueSelector">A function that yields the future value.</param>
317 /// <param name="cancellationToken">The CancellationToken for the task.</param>
318 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
319 /// <param name="creationOptions">Options to control the future's behavior.</param>
320 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
321 internal Task(Delegate valueSelector, object state, Task parent, CancellationToken cancellationToken,
322 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
323 base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
328 // Internal method used by TaskFactory<TResult>.StartNew() methods
329 internal static Task<TResult> StartNew(Task parent, Func<TResult> function, CancellationToken cancellationToken,
330 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
332 if (function == null)
334 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
336 if (scheduler == null)
338 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
341 // Create and schedule the future.
342 Task<TResult> f = new Task<TResult>(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
344 f.ScheduleAndStart(false);
348 // Internal method used by TaskFactory<TResult>.StartNew() methods
349 internal static Task<TResult> StartNew(Task parent, Func<object, TResult> function, object state, CancellationToken cancellationToken,
350 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
352 if (function == null)
354 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
356 if (scheduler == null)
358 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
361 // Create and schedule the future.
362 Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
364 f.ScheduleAndStart(false);
369 private string DebuggerDisplayResultDescription
373 return IsCompletedSuccessfully ? "" + m_result : SR.TaskT_DebuggerNoResult;
378 private string DebuggerDisplayMethodDescription
382 Delegate d = m_action;
383 return d != null ? d.Method.ToString() : "{null}";
388 // internal helper function breaks out logic used by TaskCompletionSource
389 internal bool TrySetResult(TResult result)
391 Debug.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action");
393 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
394 // has been made, (2) The result has not already been set, (3) An exception has not previously
395 // been recorded, and (4) Cancellation has not been requested.
397 // If the reservation is successful, then set the result and finish completion processing.
398 if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED,
399 TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
403 // Signal completion, for waiting tasks
405 // This logic used to be:
407 // However, that goes through a windy code path, involves many non-inlineable functions
408 // and which can be summarized more concisely with the following snippet from
409 // FinishStageTwo, omitting everything that doesn't pertain to TrySetResult.
410 Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION);
411 ContingentProperties props = m_contingentProperties;
414 NotifyParentIfPotentiallyAttachedTask();
415 props.SetCompleted();
417 FinishContinuations();
424 // Transitions the promise task into a successfully completed state with the specified result.
425 // This is dangerous, as no synchronization is used, and thus must only be used
426 // before this task is handed out to any consumers, before any continuations are hooked up,
427 // before its wait handle is accessed, etc. It's use is limited to places like in FromAsync
428 // where the operation completes synchronously, and thus we know we can forcefully complete
429 // the task, avoiding expensive completion paths, before the task is actually given to anyone.
430 internal void DangerousSetResult(TResult result)
432 Debug.Assert(!IsCompleted, "The promise must not yet be completed.");
434 // If we have a parent, we need to notify it of the completion. Take the slow path to handle that.
435 if (m_contingentProperties?.m_parent != null)
437 bool success = TrySetResult(result);
439 // Nobody else has had a chance to complete this Task yet, so we should succeed.
440 Debug.Assert(success);
445 m_stateFlags |= TASK_STATE_RAN_TO_COMPLETION;
450 /// Gets the result value of this <see cref="Task{TResult}"/>.
453 /// The get accessor for this property ensures that the asynchronous operation is complete before
454 /// returning. Once the result of the computation is available, it is stored and will be returned
455 /// immediately on later calls to <see cref="Result"/>.
457 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
458 public TResult Result
460 get { return IsWaitNotificationEnabledOrNotRanToCompletion ? GetResultCore(waitCompletionNotification: true) : m_result; }
464 /// Gets the result value of this <see cref="Task{TResult}"/> once the task has completed successfully.
467 /// This version of Result should only be used if the task completed successfully and if there's
468 /// no debugger wait notification enabled for this task.
470 internal TResult ResultOnSuccess
474 Debug.Assert(!IsWaitNotificationEnabledOrNotRanToCompletion,
475 "Should only be used when the task completed successfully and there's no wait notification enabled");
480 // Implements Result. Result delegates to this method if the result isn't already available.
481 internal TResult GetResultCore(bool waitCompletionNotification)
483 // If the result has not been calculated yet, wait for it.
484 if (!IsCompleted) InternalWait(Timeout.Infinite, default); // won't throw if task faulted or canceled; that's handled below
486 // Notify the debugger of the wait completion if it's requested such a notification
487 if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary();
489 // Throw an exception if appropriate.
490 if (!IsCompletedSuccessfully) ThrowIfExceptional(includeTaskCanceledExceptions: true);
492 // We shouldn't be here if the result has not been set.
493 Debug.Assert(IsCompletedSuccessfully, "Task<T>.Result getter: Expected result to have been set.");
498 // Allow multiple exceptions to be assigned to a promise-style task.
499 // This is useful when a TaskCompletionSource<T> stands in as a proxy
500 // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll())
501 // and the "real" task ends up with multiple exceptions, which is possible when
502 // a task has children.
504 // Called from TaskCompletionSource<T>.SetException(IEnumerable<Exception>).
505 internal bool TrySetException(object exceptionObject)
507 Debug.Assert(m_action == null, "Task<T>.TrySetException(): non-null m_action");
509 // TCS.{Try}SetException() should have checked for this
510 Debug.Assert(exceptionObject != null, "Expected non-null exceptionObject argument");
512 // Only accept these types.
514 (exceptionObject is Exception) || (exceptionObject is IEnumerable<Exception>) ||
515 (exceptionObject is ExceptionDispatchInfo) || (exceptionObject is IEnumerable<ExceptionDispatchInfo>),
516 "Expected exceptionObject to be either Exception, ExceptionDispatchInfo, or IEnumerable<> of one of those");
518 bool returnValue = false;
520 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
521 // has been made, (2) The result has not already been set, (3) An exception has not previously
522 // been recorded, and (4) Cancellation has not been requested.
524 // If the reservation is successful, then add the exception(s) and finish completion processing.
526 // The lazy initialization may not be strictly necessary, but I'd like to keep it here
527 // anyway. Some downstream logic may depend upon an inflated m_contingentProperties.
528 EnsureContingentPropertiesInitialized();
529 if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED,
530 TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
532 AddException(exceptionObject); // handles singleton exception or exception collection
540 // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder
541 // If the tokenToRecord is not None, it will be stored onto the task.
542 // This method is only valid for promise tasks.
543 internal bool TrySetCanceled(CancellationToken tokenToRecord)
545 return TrySetCanceled(tokenToRecord, null);
548 // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder
549 // If the tokenToRecord is not None, it will be stored onto the task.
550 // If the OperationCanceledException is not null, it will be stored into the task's exception holder.
551 // This method is only valid for promise tasks.
552 internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException)
554 Debug.Assert(m_action == null, "Task<T>.TrySetCanceled(): non-null m_action");
556 var ceAsEdi = cancellationException as ExceptionDispatchInfo;
558 cancellationException == null ||
559 cancellationException is OperationCanceledException ||
560 (ceAsEdi != null && ceAsEdi.SourceException is OperationCanceledException),
561 "Expected null or an OperationCanceledException");
564 bool returnValue = false;
566 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
567 // has been made, (2) The result has not already been set, (3) An exception has not previously
568 // been recorded, and (4) Cancellation has not been requested.
570 // If the reservation is successful, then record the cancellation and finish completion processing.
572 // Note: I had to access static Task variables through Task<object>
573 // instead of Task, because I have a property named Task and that
574 // was confusing the compiler.
575 if (AtomicStateUpdate(Task<object>.TASK_STATE_COMPLETION_RESERVED,
576 Task<object>.TASK_STATE_COMPLETION_RESERVED | Task<object>.TASK_STATE_CANCELED |
577 Task<object>.TASK_STATE_FAULTED | Task<object>.TASK_STATE_RAN_TO_COMPLETION))
579 RecordInternalCancellationRequest(tokenToRecord, cancellationException);
580 CancellationCleanupLogic(); // perform cancellation cleanup actions
588 /// Provides access to factory methods for creating <see cref="Task{TResult}"/> instances.
591 /// The factory returned from <see cref="Factory"/> is a default instance
592 /// of <see cref="System.Threading.Tasks.TaskFactory{TResult}"/>, as would result from using
593 /// the default constructor on the factory type.
595 public new static TaskFactory<TResult> Factory { get { return s_Factory; } }
598 /// Evaluates the value selector of the Task which is passed in as an object and stores the result.
600 internal override void InnerInvoke()
602 // Invoke the delegate
603 Debug.Assert(m_action != null);
604 var func = m_action as Func<TResult>;
610 var funcWithState = m_action as Func<object, TResult>;
611 if (funcWithState != null)
613 m_result = funcWithState(m_stateObject);
616 Debug.Fail("Invalid m_action in Task<TResult>");
619 #region Await Support
621 /// <summary>Gets an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
622 /// <returns>An awaiter instance.</returns>
623 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
624 public new TaskAwaiter<TResult> GetAwaiter()
626 return new TaskAwaiter<TResult>(this);
629 /// <summary>Configures an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
630 /// <param name="continueOnCapturedContext">
631 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
633 /// <returns>An object used to await this task.</returns>
634 public new ConfiguredTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
636 return new ConfiguredTaskAwaitable<TResult>(this, continueOnCapturedContext);
641 #region Continuation methods
643 #region Action<Task<TResult>> continuations
646 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
648 /// <param name="continuationAction">
649 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
650 /// passed the completed task as an argument.
652 /// <returns>A new continuation <see cref="Task"/>.</returns>
654 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
655 /// completed, whether it completes due to running to completion successfully, faulting due to an
656 /// unhandled exception, or exiting out early due to being canceled.
658 /// <exception cref="T:System.ArgumentNullException">
659 /// The <paramref name="continuationAction"/> argument is null.
661 public Task ContinueWith(Action<Task<TResult>> continuationAction)
663 return ContinueWith(continuationAction, TaskScheduler.Current, default, TaskContinuationOptions.None);
668 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
670 /// <param name="continuationAction">
671 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
672 /// passed the completed task as an argument.
674 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
675 /// <returns>A new continuation <see cref="Task"/>.</returns>
677 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
678 /// completed, whether it completes due to running to completion successfully, faulting due to an
679 /// unhandled exception, or exiting out early due to being canceled.
681 /// <exception cref="T:System.ArgumentNullException">
682 /// The <paramref name="continuationAction"/> argument is null.
684 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
685 /// has already been disposed.
687 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken)
689 return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
694 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
696 /// <param name="continuationAction">
697 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
698 /// passed the completed task as an argument.
700 /// <param name="scheduler">
701 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
703 /// <returns>A new continuation <see cref="Task"/>.</returns>
705 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
706 /// completed, whether it completes due to running to completion successfully, faulting due to an
707 /// unhandled exception, or exiting out early due to being canceled.
709 /// <exception cref="T:System.ArgumentNullException">
710 /// The <paramref name="continuationAction"/> argument is null.
712 /// <exception cref="T:System.ArgumentNullException">
713 /// The <paramref name="scheduler"/> argument is null.
715 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler)
717 return ContinueWith(continuationAction, scheduler, default, TaskContinuationOptions.None);
721 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
723 /// <param name="continuationAction">
724 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
725 /// passed the completed task as an argument.
727 /// <param name="continuationOptions">
728 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
730 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
731 /// well as execution options, such as <see
732 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
734 /// <returns>A new continuation <see cref="Task"/>.</returns>
736 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
737 /// completed. If the continuation criteria specified through the <paramref
738 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
739 /// instead of scheduled.
741 /// <exception cref="T:System.ArgumentNullException">
742 /// The <paramref name="continuationAction"/> argument is null.
744 /// <exception cref="T:System.ArgumentOutOfRangeException">
745 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
746 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
748 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskContinuationOptions continuationOptions)
750 return ContinueWith(continuationAction, TaskScheduler.Current, default, continuationOptions);
754 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
756 /// <param name="continuationAction">
757 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
758 /// passed the completed task as an argument.
760 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
761 /// <param name="continuationOptions">
762 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
764 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
765 /// well as execution options, such as <see
766 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
768 /// <param name="scheduler">
769 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
772 /// <returns>A new continuation <see cref="Task"/>.</returns>
774 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
775 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
776 /// are not met, the continuation task will be canceled instead of scheduled.
778 /// <exception cref="T:System.ArgumentNullException">
779 /// The <paramref name="continuationAction"/> argument is null.
781 /// <exception cref="T:System.ArgumentOutOfRangeException">
782 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
783 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
785 /// <exception cref="T:System.ArgumentNullException">
786 /// The <paramref name="scheduler"/> argument is null.
788 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
789 /// has already been disposed.
791 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken,
792 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
794 return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
797 // Same as the above overload, only with a stack mark.
798 internal Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken,
799 TaskContinuationOptions continuationOptions)
801 if (continuationAction == null)
803 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
806 if (scheduler == null)
808 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
811 TaskCreationOptions creationOptions;
812 InternalTaskOptions internalOptions;
813 CreationOptionsFromContinuationOptions(
816 out internalOptions);
818 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
819 this, continuationAction, null,
820 creationOptions, internalOptions
823 // Register the continuation. If synchronous execution is requested, this may
824 // actually invoke the continuation before returning.
825 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
827 return continuationTask;
831 #region Action<Task<TResult>, Object> continuations
834 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
836 /// <param name="continuationAction">
837 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
838 /// passed the completed task and the caller-supplied state object as arguments.
840 /// <param name="state">An object representing data to be used by the continuation action.</param>
841 /// <returns>A new continuation <see cref="Task"/>.</returns>
843 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
844 /// completed, whether it completes due to running to completion successfully, faulting due to an
845 /// unhandled exception, or exiting out early due to being canceled.
847 /// <exception cref="T:System.ArgumentNullException">
848 /// The <paramref name="continuationAction"/> argument is null.
850 public Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state)
852 return ContinueWith(continuationAction, state, TaskScheduler.Current, default, TaskContinuationOptions.None);
857 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
859 /// <param name="continuationAction">
860 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
861 /// passed the completed task and the caller-supplied state object as arguments.
863 /// <param name="state">An object representing data to be used by the continuation action.</param>
864 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
865 /// <returns>A new continuation <see cref="Task"/>.</returns>
867 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
868 /// completed, whether it completes due to running to completion successfully, faulting due to an
869 /// unhandled exception, or exiting out early due to being canceled.
871 /// <exception cref="T:System.ArgumentNullException">
872 /// The <paramref name="continuationAction"/> argument is null.
874 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
875 /// has already been disposed.
877 public Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state, CancellationToken cancellationToken)
879 return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
884 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
886 /// <param name="continuationAction">
887 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
888 /// passed the completed task and the caller-supplied state object as arguments.
890 /// <param name="state">An object representing data to be used by the continuation action.</param>
891 /// <param name="scheduler">
892 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
894 /// <returns>A new continuation <see cref="Task"/>.</returns>
896 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
897 /// completed, whether it completes due to running to completion successfully, faulting due to an
898 /// unhandled exception, or exiting out early due to being canceled.
900 /// <exception cref="T:System.ArgumentNullException">
901 /// The <paramref name="continuationAction"/> argument is null.
903 /// <exception cref="T:System.ArgumentNullException">
904 /// The <paramref name="scheduler"/> argument is null.
906 public Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state, TaskScheduler scheduler)
908 return ContinueWith(continuationAction, state, scheduler, default, TaskContinuationOptions.None);
912 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
914 /// <param name="continuationAction">
915 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
916 /// passed the completed task and the caller-supplied state object as arguments.
918 /// <param name="state">An object representing data to be used by the continuation action.</param>
919 /// <param name="continuationOptions">
920 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
922 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
923 /// well as execution options, such as <see
924 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
926 /// <returns>A new continuation <see cref="Task"/>.</returns>
928 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
929 /// completed. If the continuation criteria specified through the <paramref
930 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
931 /// instead of scheduled.
933 /// <exception cref="T:System.ArgumentNullException">
934 /// The <paramref name="continuationAction"/> argument is null.
936 /// <exception cref="T:System.ArgumentOutOfRangeException">
937 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
938 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
940 public Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
942 return ContinueWith(continuationAction, state, TaskScheduler.Current, default, continuationOptions);
946 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
948 /// <param name="continuationAction">
949 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
950 /// passed the completed task and the caller-supplied state object as arguments.
952 /// <param name="state">An object representing data to be used by the continuation action.</param>
953 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
954 /// <param name="continuationOptions">
955 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
957 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
958 /// well as execution options, such as <see
959 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
961 /// <param name="scheduler">
962 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
965 /// <returns>A new continuation <see cref="Task"/>.</returns>
967 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
968 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
969 /// are not met, the continuation task will be canceled instead of scheduled.
971 /// <exception cref="T:System.ArgumentNullException">
972 /// The <paramref name="continuationAction"/> argument is null.
974 /// <exception cref="T:System.ArgumentOutOfRangeException">
975 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
976 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
978 /// <exception cref="T:System.ArgumentNullException">
979 /// The <paramref name="scheduler"/> argument is null.
981 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
982 /// has already been disposed.
984 public Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state, CancellationToken cancellationToken,
985 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
987 return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
990 // Same as the above overload, only with a stack mark.
991 internal Task ContinueWith(Action<Task<TResult>, object> continuationAction, object state, TaskScheduler scheduler, CancellationToken cancellationToken,
992 TaskContinuationOptions continuationOptions)
994 if (continuationAction == null)
996 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
999 if (scheduler == null)
1001 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1004 TaskCreationOptions creationOptions;
1005 InternalTaskOptions internalOptions;
1006 CreationOptionsFromContinuationOptions(
1007 continuationOptions,
1008 out creationOptions,
1009 out internalOptions);
1011 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
1012 this, continuationAction, state,
1013 creationOptions, internalOptions
1016 // Register the continuation. If synchronous execution is requested, this may
1017 // actually invoke the continuation before returning.
1018 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
1020 return continuationTask;
1025 #region Func<Task<TResult>,TNewResult> continuations
1028 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1030 /// <typeparam name="TNewResult">
1031 /// The type of the result produced by the continuation.
1033 /// <param name="continuationFunction">
1034 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1035 /// passed the completed task as an argument.
1037 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1039 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1040 /// task has completed, whether it completes due to running to completion successfully, faulting due
1041 /// to an unhandled exception, or exiting out early due to being canceled.
1043 /// <exception cref="T:System.ArgumentNullException">
1044 /// The <paramref name="continuationFunction"/> argument is null.
1046 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction)
1048 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default, TaskContinuationOptions.None);
1053 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1055 /// <typeparam name="TNewResult">
1056 /// The type of the result produced by the continuation.
1058 /// <param name="continuationFunction">
1059 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1060 /// passed the completed task as an argument.
1062 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1063 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1065 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1066 /// task has completed, whether it completes due to running to completion successfully, faulting due
1067 /// to an unhandled exception, or exiting out early due to being canceled.
1069 /// <exception cref="T:System.ArgumentNullException">
1070 /// The <paramref name="continuationFunction"/> argument is null.
1072 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1073 /// has already been disposed.
1075 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken)
1077 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
1081 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1083 /// <typeparam name="TNewResult">
1084 /// The type of the result produced by the continuation.
1086 /// <param name="continuationFunction">
1087 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1088 /// passed the completed task as an argument.
1090 /// <param name="scheduler">
1091 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
1093 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1095 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1096 /// completed, whether it completes due to running to completion successfully, faulting due to an
1097 /// unhandled exception, or exiting out early due to being canceled.
1099 /// <exception cref="T:System.ArgumentNullException">
1100 /// The <paramref name="continuationFunction"/> argument is null.
1102 /// <exception cref="T:System.ArgumentNullException">
1103 /// The <paramref name="scheduler"/> argument is null.
1105 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler)
1107 return ContinueWith<TNewResult>(continuationFunction, scheduler, default, TaskContinuationOptions.None);
1111 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1113 /// <typeparam name="TNewResult">
1114 /// The type of the result produced by the continuation.
1116 /// <param name="continuationFunction">
1117 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1118 /// passed the completed task as an argument.
1120 /// <param name="continuationOptions">
1121 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1123 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1124 /// well as execution options, such as <see
1125 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1127 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1130 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1131 /// task has completed, whether it completes due to running to completion successfully, faulting due
1132 /// to an unhandled exception, or exiting out early due to being canceled.
1135 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1136 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1137 /// from the ContinueWith call.
1140 /// <exception cref="T:System.ArgumentNullException">
1141 /// The <paramref name="continuationFunction"/> argument is null.
1143 /// <exception cref="T:System.ArgumentOutOfRangeException">
1144 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1145 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1147 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions)
1149 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default, continuationOptions);
1153 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1155 /// <typeparam name="TNewResult">
1156 /// The type of the result produced by the continuation.
1158 /// <param name="continuationFunction">
1159 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be passed as
1160 /// an argument this completed task.
1162 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1163 /// <param name="continuationOptions">
1164 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1166 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1167 /// well as execution options, such as <see
1168 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1170 /// <param name="scheduler">
1171 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1174 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1177 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1178 /// completed, whether it completes due to running to completion successfully, faulting due to an
1179 /// unhandled exception, or exiting out early due to being canceled.
1182 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1183 /// This task's completion state will be transferred to the task returned from the
1184 /// ContinueWith call.
1187 /// <exception cref="T:System.ArgumentNullException">
1188 /// The <paramref name="continuationFunction"/> argument is null.
1190 /// <exception cref="T:System.ArgumentOutOfRangeException">
1191 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1192 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1194 /// <exception cref="T:System.ArgumentNullException">
1195 /// The <paramref name="scheduler"/> argument is null.
1197 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1198 /// has already been disposed.
1200 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken,
1201 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1203 return ContinueWith<TNewResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
1206 // Same as the above overload, just with a stack mark.
1207 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler,
1208 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
1210 if (continuationFunction == null)
1212 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
1215 if (scheduler == null)
1217 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1220 TaskCreationOptions creationOptions;
1221 InternalTaskOptions internalOptions;
1222 CreationOptionsFromContinuationOptions(
1223 continuationOptions,
1224 out creationOptions,
1225 out internalOptions);
1227 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
1228 this, continuationFunction, null,
1229 creationOptions, internalOptions
1232 // Register the continuation. If synchronous execution is requested, this may
1233 // actually invoke the continuation before returning.
1234 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1236 return continuationFuture;
1240 #region Func<Task<TResult>, Object,TNewResult> continuations
1243 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1245 /// <typeparam name="TNewResult">
1246 /// The type of the result produced by the continuation.
1248 /// <param name="continuationFunction">
1249 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1250 /// passed the completed task and the caller-supplied state object as arguments.
1252 /// <param name="state">An object representing data to be used by the continuation function.</param>
1253 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1255 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1256 /// task has completed, whether it completes due to running to completion successfully, faulting due
1257 /// to an unhandled exception, or exiting out early due to being canceled.
1259 /// <exception cref="T:System.ArgumentNullException">
1260 /// The <paramref name="continuationFunction"/> argument is null.
1262 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state)
1264 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default, TaskContinuationOptions.None);
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
1276 /// passed the completed task and the caller-supplied state object as arguments.
1278 /// <param name="state">An object representing data to be used by the continuation function.</param>
1279 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1280 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1282 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1283 /// task has completed, whether it completes due to running to completion successfully, faulting due
1284 /// to an unhandled exception, or exiting out early due to being canceled.
1286 /// <exception cref="T:System.ArgumentNullException">
1287 /// The <paramref name="continuationFunction"/> argument is null.
1289 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1290 /// has already been disposed.
1292 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state,
1293 CancellationToken cancellationToken)
1295 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
1299 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1301 /// <typeparam name="TNewResult">
1302 /// The type of the result produced by the continuation.
1304 /// <param name="continuationFunction">
1305 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1306 /// passed the completed task and the caller-supplied state object as arguments.
1308 /// <param name="state">An object representing data to be used by the continuation function.</param>
1309 /// <param name="scheduler">
1310 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
1312 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1314 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1315 /// completed, whether it completes due to running to completion successfully, faulting due to an
1316 /// unhandled exception, or exiting out early due to being canceled.
1318 /// <exception cref="T:System.ArgumentNullException">
1319 /// The <paramref name="continuationFunction"/> argument is null.
1321 /// <exception cref="T:System.ArgumentNullException">
1322 /// The <paramref name="scheduler"/> argument is null.
1324 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state,
1325 TaskScheduler scheduler)
1327 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, default, TaskContinuationOptions.None);
1331 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1333 /// <typeparam name="TNewResult">
1334 /// The type of the result produced by the continuation.
1336 /// <param name="continuationFunction">
1337 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1338 /// passed the completed task and the caller-supplied state object as arguments.
1340 /// <param name="state">An object representing data to be used by the continuation function.</param>
1341 /// <param name="continuationOptions">
1342 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1344 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1345 /// well as execution options, such as <see
1346 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1348 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1351 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1352 /// task has completed, whether it completes due to running to completion successfully, faulting due
1353 /// to an unhandled exception, or exiting out early due to being canceled.
1356 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1357 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1358 /// from the ContinueWith call.
1361 /// <exception cref="T:System.ArgumentNullException">
1362 /// The <paramref name="continuationFunction"/> argument is null.
1364 /// <exception cref="T:System.ArgumentOutOfRangeException">
1365 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1366 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1368 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state,
1369 TaskContinuationOptions continuationOptions)
1371 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default, continuationOptions);
1375 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1377 /// <typeparam name="TNewResult">
1378 /// The type of the result produced by the continuation.
1380 /// <param name="continuationFunction">
1381 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1382 /// passed the completed task and the caller-supplied state object as arguments.
1384 /// <param name="state">An object representing data to be used by the continuation function.</param>
1385 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1386 /// <param name="continuationOptions">
1387 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1389 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1390 /// well as execution options, such as <see
1391 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1393 /// <param name="scheduler">
1394 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1397 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1400 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1401 /// completed, whether it completes due to running to completion successfully, faulting due to an
1402 /// unhandled exception, or exiting out early due to being canceled.
1405 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1406 /// This task's completion state will be transferred to the task returned from the
1407 /// ContinueWith call.
1410 /// <exception cref="T:System.ArgumentNullException">
1411 /// The <paramref name="continuationFunction"/> argument is null.
1413 /// <exception cref="T:System.ArgumentOutOfRangeException">
1414 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1415 /// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1417 /// <exception cref="T:System.ArgumentNullException">
1418 /// The <paramref name="scheduler"/> argument is null.
1420 /// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1421 /// has already been disposed.
1423 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state,
1424 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1426 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
1429 // Same as the above overload, just with a stack mark.
1430 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object, TNewResult> continuationFunction, object state,
1431 TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
1433 if (continuationFunction == null)
1435 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
1438 if (scheduler == null)
1440 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1443 TaskCreationOptions creationOptions;
1444 InternalTaskOptions internalOptions;
1445 CreationOptionsFromContinuationOptions(
1446 continuationOptions,
1447 out creationOptions,
1448 out internalOptions);
1450 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
1451 this, continuationFunction, state,
1452 creationOptions, internalOptions
1455 // Register the continuation. If synchronous execution is requested, this may
1456 // actually invoke the continuation before returning.
1457 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1459 return continuationFuture;
1467 // Proxy class for better debugging experience
1468 internal class SystemThreadingTasks_FutureDebugView<TResult>
1470 private Task<TResult> m_task;
1472 public SystemThreadingTasks_FutureDebugView(Task<TResult> task)
1477 public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default; } }
1478 public object AsyncState { get { return m_task.AsyncState; } }
1479 public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } }
1480 public Exception Exception { get { return m_task.Exception; } }
1481 public int Id { get { return m_task.Id; } }
1482 public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } }
1483 public TaskStatus Status { get { return m_task.Status; } }