Fix StyleCop warning SA1005 (single line comment spacing)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Threading / Tasks / Future.cs
blob052b63f4674c4d5ced5e04c38efaccb1b00e4b4b
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 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
6 //
7 //
8 //
9 // A task that produces a value.
11 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
13 using System.Diagnostics;
14 using System.Diagnostics.CodeAnalysis;
15 using System.Runtime.CompilerServices;
17 namespace System.Threading.Tasks
19 /// <summary>
20 /// Represents an asynchronous operation that produces a result at some time in the future.
21 /// </summary>
22 /// <typeparam name="TResult">
23 /// The type of the result produced by this <see cref="Task{TResult}"/>.
24 /// </typeparam>
25 /// <remarks>
26 /// <para>
27 /// <see cref="Task{TResult}"/> instances may be created in a variety of ways. The most common approach is by
28 /// using the task's <see cref="Factory"/> property to retrieve a <see
29 /// cref="System.Threading.Tasks.TaskFactory{TResult}"/> instance that can be used to create tasks for several
30 /// purposes. For example, to create a <see cref="Task{TResult}"/> that runs a function, the factory's StartNew
31 /// method may be used:
32 /// <code>
33 /// // C#
34 /// var t = Task&lt;int&gt;.Factory.StartNew(() => GenerateResult());
35 /// - or -
36 /// var t = Task.Factory.StartNew(() => GenerateResult());
37 ///
38 /// ' Visual Basic
39 /// Dim t = Task&lt;int&gt;.Factory.StartNew(Function() GenerateResult())
40 /// - or -
41 /// Dim t = Task.Factory.StartNew(Function() GenerateResult())
42 /// </code>
43 /// </para>
44 /// <para>
45 /// The <see cref="Task{TResult}"/> class also provides constructors that initialize the task but that do not
46 /// schedule it for execution. For performance reasons, the StartNew method should be the
47 /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation
48 /// and scheduling must be separated, the constructors may be used, and the task's
49 /// <see cref="System.Threading.Tasks.Task.Start()">Start</see>
50 /// method may then be used to schedule the task for execution at a later time.
51 /// </para>
52 /// <para>
53 /// All members of <see cref="Task{TResult}"/>, except for
54 /// <see cref="System.Threading.Tasks.Task.Dispose()">Dispose</see>, are thread-safe
55 /// and may be used from multiple threads concurrently.
56 /// </para>
57 /// </remarks>
58 [DebuggerTypeProxy(typeof(SystemThreadingTasks_FutureDebugView<>))]
59 [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")]
60 public class Task<TResult> : Task
62 // The value itself, if set.
63 [MaybeNull] internal TResult m_result = default!;
65 private static readonly TaskFactory<TResult> s_Factory = new TaskFactory<TResult>();
67 // Extract rarely used helper for a static method in a separate type so that the Func<Task<Task>, Task<TResult>>
68 // generic instantiations don't contribute to all Task instantiations, but only those where WhenAny is used.
69 internal static class TaskWhenAnyCast
71 // Delegate used by:
72 // public static Task<Task<TResult>> WhenAny<TResult>(IEnumerable<Task<TResult>> tasks);
73 // public static Task<Task<TResult>> WhenAny<TResult>(params Task<TResult>[] tasks);
74 // Used to "cast" from Task<Task> to Task<Task<TResult>>.
75 internal static readonly Func<Task<Task>, Task<TResult>> Value = completed => (Task<TResult>)completed.Result;
78 // Construct a promise-style task without any options.
79 internal Task() :
80 base()
84 // Construct a promise-style task with state and options.
85 internal Task(object? state, TaskCreationOptions options) :
86 base(state, options, promiseStyle: true)
91 // Construct a pre-completed Task<TResult>
92 internal Task(TResult result) :
93 base(false, TaskCreationOptions.None, default)
95 m_result = result;
98 internal Task(bool canceled, [AllowNull] TResult result, TaskCreationOptions creationOptions, CancellationToken ct)
99 : base(canceled, creationOptions, ct)
101 if (!canceled)
103 m_result = result;
107 /// <summary>
108 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
109 /// </summary>
110 /// <param name="function">
111 /// The delegate that represents the code to execute in the task. When the function has completed,
112 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
113 /// </param>
114 /// <exception cref="System.ArgumentException">
115 /// The <paramref name="function"/> argument is null.
116 /// </exception>
117 public Task(Func<TResult> function)
118 : this(function, null, default,
119 TaskCreationOptions.None, InternalTaskOptions.None, null)
124 /// <summary>
125 /// Initializes a new <see cref="Task{TResult}"/> with the specified function.
126 /// </summary>
127 /// <param name="function">
128 /// The delegate that represents the code to execute in the task. When the function has completed,
129 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
130 /// </param>
131 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to this task.</param>
132 /// <exception cref="System.ArgumentException">
133 /// The <paramref name="function"/> argument is null.
134 /// </exception>
135 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
136 /// has already been disposed.
137 /// </exception>
138 public Task(Func<TResult> function, CancellationToken cancellationToken)
139 : this(function, null, cancellationToken,
140 TaskCreationOptions.None, InternalTaskOptions.None, null)
144 /// <summary>
145 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
146 /// </summary>
147 /// <param name="function">
148 /// The delegate that represents the code to execute in the task. When the function has completed,
149 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
150 /// </param>
151 /// <param name="creationOptions">
152 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
153 /// customize the task's behavior.
154 /// </param>
155 /// <exception cref="System.ArgumentException">
156 /// The <paramref name="function"/> argument is null.
157 /// </exception>
158 /// <exception cref="System.ArgumentOutOfRangeException">
159 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
160 /// cref="System.Threading.Tasks.TaskCreationOptions"/>.
161 /// </exception>
162 public Task(Func<TResult> function, TaskCreationOptions creationOptions)
163 : this(function, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null)
167 /// <summary>
168 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and creation options.
169 /// </summary>
170 /// <param name="function">
171 /// The delegate that represents the code to execute in the task. When the function has completed,
172 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
173 /// </param>
174 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
175 /// <param name="creationOptions">
176 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
177 /// customize the task's behavior.
178 /// </param>
179 /// <exception cref="System.ArgumentException">
180 /// The <paramref name="function"/> argument is null.
181 /// </exception>
182 /// <exception cref="System.ArgumentOutOfRangeException">
183 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
184 /// cref="System.Threading.Tasks.TaskCreationOptions"/>.
185 /// </exception>
186 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
187 /// has already been disposed.
188 /// </exception>
189 public Task(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
190 : this(function, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
194 /// <summary>
195 /// Initializes a new <see cref="Task{TResult}"/> with the specified function and state.
196 /// </summary>
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.
200 /// </param>
201 /// <param name="state">An object representing data to be used by the action.</param>
202 /// <exception cref="System.ArgumentException">
203 /// The <paramref name="function"/> argument is null.
204 /// </exception>
205 public Task(Func<object?, TResult> function, object? state)
206 : this(function, state, null, default,
207 TaskCreationOptions.None, InternalTaskOptions.None, null)
211 /// <summary>
212 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
213 /// </summary>
214 /// <param name="function">
215 /// The delegate that represents the code to execute in the task. When the function has completed,
216 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
217 /// </param>
218 /// <param name="state">An object representing data to be used by the function.</param>
219 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</param>
220 /// <exception cref="System.ArgumentException">
221 /// The <paramref name="function"/> argument is null.
222 /// </exception>
223 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
224 /// has already been disposed.
225 /// </exception>
226 public Task(Func<object?, TResult> function, object? state, CancellationToken cancellationToken)
227 : this(function, state, null, cancellationToken,
228 TaskCreationOptions.None, InternalTaskOptions.None, null)
232 /// <summary>
233 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
234 /// </summary>
235 /// <param name="function">
236 /// The delegate that represents the code to execute in the task. When the function has completed,
237 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
238 /// </param>
239 /// <param name="state">An object representing data to be used by the function.</param>
240 /// <param name="creationOptions">
241 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
242 /// customize the task's behavior.
243 /// </param>
244 /// <exception cref="System.ArgumentException">
245 /// The <paramref name="function"/> argument is null.
246 /// </exception>
247 /// <exception cref="System.ArgumentOutOfRangeException">
248 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
249 /// cref="System.Threading.Tasks.TaskCreationOptions"/>.
250 /// </exception>
251 public Task(Func<object?, TResult> function, object? state, TaskCreationOptions creationOptions)
252 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default,
253 creationOptions, InternalTaskOptions.None, null)
258 /// <summary>
259 /// Initializes a new <see cref="Task{TResult}"/> with the specified action, state, and options.
260 /// </summary>
261 /// <param name="function">
262 /// The delegate that represents the code to execute in the task. When the function has completed,
263 /// the task's <see cref="Result"/> property will be set to return the result value of the function.
264 /// </param>
265 /// <param name="state">An object representing data to be used by the function.</param>
266 /// <param name="cancellationToken">The <see cref="CancellationToken"/> to be assigned to the new task.</param>
267 /// <param name="creationOptions">
268 /// The <see cref="System.Threading.Tasks.TaskCreationOptions">TaskCreationOptions</see> used to
269 /// customize the task's behavior.
270 /// </param>
271 /// <exception cref="System.ArgumentException">
272 /// The <paramref name="function"/> argument is null.
273 /// </exception>
274 /// <exception cref="System.ArgumentOutOfRangeException">
275 /// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
276 /// cref="System.Threading.Tasks.TaskCreationOptions"/>.
277 /// </exception>
278 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
279 /// has already been disposed.
280 /// </exception>
281 public Task(Func<object?, TResult> function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
282 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken,
283 creationOptions, InternalTaskOptions.None, null)
287 /// <summary>
288 /// Creates a new future object.
289 /// </summary>
290 /// <param name="parent">The parent task for this future.</param>
291 /// <param name="valueSelector">A function that yields the future value.</param>
292 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
293 /// <param name="cancellationToken">The CancellationToken for the task.</param>
294 /// <param name="creationOptions">Options to control the future's behavior.</param>
295 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
296 internal Task(Func<TResult> valueSelector, Task? parent, CancellationToken cancellationToken,
297 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) :
298 base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler)
302 /// <summary>
303 /// Creates a new future object.
304 /// </summary>
305 /// <param name="parent">The parent task for this future.</param>
306 /// <param name="state">An object containing data to be used by the action; may be null.</param>
307 /// <param name="valueSelector">A function that yields the future value.</param>
308 /// <param name="cancellationToken">The CancellationToken for the task.</param>
309 /// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
310 /// <param name="creationOptions">Options to control the future's behavior.</param>
311 /// <param name="internalOptions">Internal options to control the future's behavior.</param>
312 internal Task(Delegate valueSelector, object? state, Task? parent, CancellationToken cancellationToken,
313 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) :
314 base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
319 // Internal method used by TaskFactory<TResult>.StartNew() methods
320 internal static Task<TResult> StartNew(Task? parent, Func<TResult> function, CancellationToken cancellationToken,
321 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
323 if (function == null)
325 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
327 if (scheduler == null)
329 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
332 // Create and schedule the future.
333 Task<TResult> f = new Task<TResult>(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
335 f.ScheduleAndStart(false);
336 return f;
339 // Internal method used by TaskFactory<TResult>.StartNew() methods
340 internal static Task<TResult> StartNew(Task? parent, Func<object?, TResult> function, object? state, CancellationToken cancellationToken,
341 TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
343 if (function == null)
345 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);
347 if (scheduler == null)
349 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
352 // Create and schedule the future.
353 Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
355 f.ScheduleAndStart(false);
356 return f;
359 // Debugger support
360 private string DebuggerDisplayResultDescription =>
361 IsCompletedSuccessfully ? "" + m_result : SR.TaskT_DebuggerNoResult;
363 // Debugger support
364 private string DebuggerDisplayMethodDescription =>
365 m_action?.Method.ToString() ?? "{null}";
368 // internal helper function breaks out logic used by TaskCompletionSource
369 internal bool TrySetResult([AllowNull] TResult result)
371 Debug.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action");
373 bool returnValue = false;
375 // "Reserve" the completion for this task, while making sure that: (1) No prior reservation
376 // has been made, (2) The result has not already been set, (3) An exception has not previously
377 // been recorded, and (4) Cancellation has not been requested.
379 // If the reservation is successful, then set the result and finish completion processing.
380 if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED,
381 TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED))
383 m_result = result;
385 // Signal completion, for waiting tasks
387 // This logic used to be:
388 // Finish(false);
389 // However, that goes through a windy code path, involves many non-inlineable functions
390 // and which can be summarized more concisely with the following snippet from
391 // FinishStageTwo, omitting everything that doesn't pertain to TrySetResult.
392 Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION);
393 ContingentProperties? props = m_contingentProperties;
394 if (props != null)
396 NotifyParentIfPotentiallyAttachedTask();
397 props.SetCompleted();
399 FinishContinuations();
400 returnValue = true;
403 return returnValue;
406 // Transitions the promise task into a successfully completed state with the specified result.
407 // This is dangerous, as no synchronization is used, and thus must only be used
408 // before this task is handed out to any consumers, before any continuations are hooked up,
409 // before its wait handle is accessed, etc. It's use is limited to places like in FromAsync
410 // where the operation completes synchronously, and thus we know we can forcefully complete
411 // the task, avoiding expensive completion paths, before the task is actually given to anyone.
412 internal void DangerousSetResult(TResult result)
414 Debug.Assert(!IsCompleted, "The promise must not yet be completed.");
416 // If we have a parent, we need to notify it of the completion. Take the slow path to handle that.
417 if (m_contingentProperties?.m_parent != null)
419 bool success = TrySetResult(result);
421 // Nobody else has had a chance to complete this Task yet, so we should succeed.
422 Debug.Assert(success);
424 else
426 m_result = result;
427 m_stateFlags |= TASK_STATE_RAN_TO_COMPLETION;
431 /// <summary>
432 /// Gets the result value of this <see cref="Task{TResult}"/>.
433 /// </summary>
434 /// <remarks>
435 /// The get accessor for this property ensures that the asynchronous operation is complete before
436 /// returning. Once the result of the computation is available, it is stored and will be returned
437 /// immediately on later calls to <see cref="Result"/>.
438 /// </remarks>
439 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
440 public TResult Result =>
441 IsWaitNotificationEnabledOrNotRanToCompletion ?
442 GetResultCore(waitCompletionNotification: true) :
443 m_result;
445 /// <summary>
446 /// Gets the result value of this <see cref="Task{TResult}"/> once the task has completed successfully.
447 /// </summary>
448 /// <remarks>
449 /// This version of Result should only be used if the task completed successfully and if there's
450 /// no debugger wait notification enabled for this task.
451 /// </remarks>
452 internal TResult ResultOnSuccess
456 Debug.Assert(!IsWaitNotificationEnabledOrNotRanToCompletion,
457 "Should only be used when the task completed successfully and there's no wait notification enabled");
458 return m_result;
462 // Implements Result. Result delegates to this method if the result isn't already available.
463 internal TResult GetResultCore(bool waitCompletionNotification)
465 // If the result has not been calculated yet, wait for it.
466 if (!IsCompleted) InternalWait(Timeout.Infinite, default); // won't throw if task faulted or canceled; that's handled below
468 // Notify the debugger of the wait completion if it's requested such a notification
469 if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary();
471 // Throw an exception if appropriate.
472 if (!IsCompletedSuccessfully) ThrowIfExceptional(includeTaskCanceledExceptions: true);
474 // We shouldn't be here if the result has not been set.
475 Debug.Assert(IsCompletedSuccessfully, "Task<T>.Result getter: Expected result to have been set.");
477 return m_result;
480 /// <summary>
481 /// Provides access to factory methods for creating <see cref="Task{TResult}"/> instances.
482 /// </summary>
483 /// <remarks>
484 /// The factory returned from <see cref="Factory"/> is a default instance
485 /// of <see cref="System.Threading.Tasks.TaskFactory{TResult}"/>, as would result from using
486 /// the default constructor on the factory type.
487 /// </remarks>
488 public static new TaskFactory<TResult> Factory => s_Factory;
490 /// <summary>
491 /// Evaluates the value selector of the Task which is passed in as an object and stores the result.
492 /// </summary>
493 internal override void InnerInvoke()
495 // Invoke the delegate
496 Debug.Assert(m_action != null);
497 if (m_action is Func<TResult> func)
499 m_result = func();
500 return;
503 if (m_action is Func<object?, TResult> funcWithState)
505 m_result = funcWithState(m_stateObject);
506 return;
508 Debug.Fail("Invalid m_action in Task<TResult>");
511 #region Await Support
513 /// <summary>Gets an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
514 /// <returns>An awaiter instance.</returns>
515 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
516 public new TaskAwaiter<TResult> GetAwaiter()
518 return new TaskAwaiter<TResult>(this);
521 /// <summary>Configures an awaiter used to await this <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
522 /// <param name="continueOnCapturedContext">
523 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
524 /// </param>
525 /// <returns>An object used to await this task.</returns>
526 public new ConfiguredTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
528 return new ConfiguredTaskAwaitable<TResult>(this, continueOnCapturedContext);
531 #endregion
533 #region Continuation methods
535 #region Action<Task<TResult>> continuations
537 /// <summary>
538 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
539 /// </summary>
540 /// <param name="continuationAction">
541 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
542 /// passed the completed task as an argument.
543 /// </param>
544 /// <returns>A new continuation <see cref="Task"/>.</returns>
545 /// <remarks>
546 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
547 /// completed, whether it completes due to running to completion successfully, faulting due to an
548 /// unhandled exception, or exiting out early due to being canceled.
549 /// </remarks>
550 /// <exception cref="System.ArgumentNullException">
551 /// The <paramref name="continuationAction"/> argument is null.
552 /// </exception>
553 public Task ContinueWith(Action<Task<TResult>> continuationAction)
555 return ContinueWith(continuationAction, TaskScheduler.Current, default, TaskContinuationOptions.None);
559 /// <summary>
560 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
561 /// </summary>
562 /// <param name="continuationAction">
563 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
564 /// passed the completed task as an argument.
565 /// </param>
566 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
567 /// <returns>A new continuation <see cref="Task"/>.</returns>
568 /// <remarks>
569 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
570 /// completed, whether it completes due to running to completion successfully, faulting due to an
571 /// unhandled exception, or exiting out early due to being canceled.
572 /// </remarks>
573 /// <exception cref="System.ArgumentNullException">
574 /// The <paramref name="continuationAction"/> argument is null.
575 /// </exception>
576 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
577 /// has already been disposed.
578 /// </exception>
579 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken)
581 return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
585 /// <summary>
586 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
587 /// </summary>
588 /// <param name="continuationAction">
589 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
590 /// passed the completed task as an argument.
591 /// </param>
592 /// <param name="scheduler">
593 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
594 /// </param>
595 /// <returns>A new continuation <see cref="Task"/>.</returns>
596 /// <remarks>
597 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
598 /// completed, whether it completes due to running to completion successfully, faulting due to an
599 /// unhandled exception, or exiting out early due to being canceled.
600 /// </remarks>
601 /// <exception cref="System.ArgumentNullException">
602 /// The <paramref name="continuationAction"/> argument is null.
603 /// </exception>
604 /// <exception cref="System.ArgumentNullException">
605 /// The <paramref name="scheduler"/> argument is null.
606 /// </exception>
607 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler)
609 return ContinueWith(continuationAction, scheduler, default, TaskContinuationOptions.None);
612 /// <summary>
613 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
614 /// </summary>
615 /// <param name="continuationAction">
616 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
617 /// passed the completed task as an argument.
618 /// </param>
619 /// <param name="continuationOptions">
620 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
621 /// as <see
622 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
623 /// well as execution options, such as <see
624 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
625 /// </param>
626 /// <returns>A new continuation <see cref="Task"/>.</returns>
627 /// <remarks>
628 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
629 /// completed. If the continuation criteria specified through the <paramref
630 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
631 /// instead of scheduled.
632 /// </remarks>
633 /// <exception cref="System.ArgumentNullException">
634 /// The <paramref name="continuationAction"/> argument is null.
635 /// </exception>
636 /// <exception cref="System.ArgumentOutOfRangeException">
637 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
638 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
639 /// </exception>
640 public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskContinuationOptions continuationOptions)
642 return ContinueWith(continuationAction, TaskScheduler.Current, default, continuationOptions);
645 /// <summary>
646 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
647 /// </summary>
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.
651 /// </param>
652 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
653 /// <param name="continuationOptions">
654 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
655 /// as <see
656 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
657 /// well as execution options, such as <see
658 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
659 /// </param>
660 /// <param name="scheduler">
661 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
662 /// execution.
663 /// </param>
664 /// <returns>A new continuation <see cref="Task"/>.</returns>
665 /// <remarks>
666 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
667 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
668 /// are not met, the continuation task will be canceled instead of scheduled.
669 /// </remarks>
670 /// <exception cref="System.ArgumentNullException">
671 /// The <paramref name="continuationAction"/> argument is null.
672 /// </exception>
673 /// <exception cref="System.ArgumentOutOfRangeException">
674 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
675 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
676 /// </exception>
677 /// <exception cref="System.ArgumentNullException">
678 /// The <paramref name="scheduler"/> argument is null.
679 /// </exception>
680 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
681 /// has already been disposed.
682 /// </exception>
683 public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken,
684 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
686 return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
689 // Same as the above overload, only with a stack mark.
690 internal Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken,
691 TaskContinuationOptions continuationOptions)
693 if (continuationAction == null)
695 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
698 if (scheduler == null)
700 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
703 TaskCreationOptions creationOptions;
704 InternalTaskOptions internalOptions;
705 CreationOptionsFromContinuationOptions(
706 continuationOptions,
707 out creationOptions,
708 out internalOptions);
710 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
711 this, continuationAction, null,
712 creationOptions, internalOptions
715 // Register the continuation. If synchronous execution is requested, this may
716 // actually invoke the continuation before returning.
717 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
719 return continuationTask;
721 #endregion
723 #region Action<Task<TResult>, Object> continuations
725 /// <summary>
726 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
727 /// </summary>
728 /// <param name="continuationAction">
729 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
730 /// passed the completed task and the caller-supplied state object as arguments.
731 /// </param>
732 /// <param name="state">An object representing data to be used by the continuation action.</param>
733 /// <returns>A new continuation <see cref="Task"/>.</returns>
734 /// <remarks>
735 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
736 /// completed, whether it completes due to running to completion successfully, faulting due to an
737 /// unhandled exception, or exiting out early due to being canceled.
738 /// </remarks>
739 /// <exception cref="System.ArgumentNullException">
740 /// The <paramref name="continuationAction"/> argument is null.
741 /// </exception>
742 public Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state)
744 return ContinueWith(continuationAction, state, TaskScheduler.Current, default, TaskContinuationOptions.None);
748 /// <summary>
749 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
750 /// </summary>
751 /// <param name="continuationAction">
752 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
753 /// passed the completed task and the caller-supplied state object as arguments.
754 /// </param>
755 /// <param name="state">An object representing data to be used by the continuation action.</param>
756 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
757 /// <returns>A new continuation <see cref="Task"/>.</returns>
758 /// <remarks>
759 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
760 /// completed, whether it completes due to running to completion successfully, faulting due to an
761 /// unhandled exception, or exiting out early due to being canceled.
762 /// </remarks>
763 /// <exception cref="System.ArgumentNullException">
764 /// The <paramref name="continuationAction"/> argument is null.
765 /// </exception>
766 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
767 /// has already been disposed.
768 /// </exception>
769 public Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state, CancellationToken cancellationToken)
771 return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
775 /// <summary>
776 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
777 /// </summary>
778 /// <param name="continuationAction">
779 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
780 /// passed the completed task and the caller-supplied state object as arguments.
781 /// </param>
782 /// <param name="state">An object representing data to be used by the continuation action.</param>
783 /// <param name="scheduler">
784 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
785 /// </param>
786 /// <returns>A new continuation <see cref="Task"/>.</returns>
787 /// <remarks>
788 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
789 /// completed, whether it completes due to running to completion successfully, faulting due to an
790 /// unhandled exception, or exiting out early due to being canceled.
791 /// </remarks>
792 /// <exception cref="System.ArgumentNullException">
793 /// The <paramref name="continuationAction"/> argument is null.
794 /// </exception>
795 /// <exception cref="System.ArgumentNullException">
796 /// The <paramref name="scheduler"/> argument is null.
797 /// </exception>
798 public Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state, TaskScheduler scheduler)
800 return ContinueWith(continuationAction, state, scheduler, default, TaskContinuationOptions.None);
803 /// <summary>
804 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
805 /// </summary>
806 /// <param name="continuationAction">
807 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
808 /// passed the completed task and the caller-supplied state object as arguments.
809 /// </param>
810 /// <param name="state">An object representing data to be used by the continuation action.</param>
811 /// <param name="continuationOptions">
812 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
813 /// as <see
814 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
815 /// well as execution options, such as <see
816 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
817 /// </param>
818 /// <returns>A new continuation <see cref="Task"/>.</returns>
819 /// <remarks>
820 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
821 /// completed. If the continuation criteria specified through the <paramref
822 /// name="continuationOptions"/> parameter are not met, the continuation task will be canceled
823 /// instead of scheduled.
824 /// </remarks>
825 /// <exception cref="System.ArgumentNullException">
826 /// The <paramref name="continuationAction"/> argument is null.
827 /// </exception>
828 /// <exception cref="System.ArgumentOutOfRangeException">
829 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
830 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
831 /// </exception>
832 public Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state, TaskContinuationOptions continuationOptions)
834 return ContinueWith(continuationAction, state, TaskScheduler.Current, default, continuationOptions);
837 /// <summary>
838 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
839 /// </summary>
840 /// <param name="continuationAction">
841 /// An action to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
842 /// passed the completed task and the caller-supplied state object as arguments.
843 /// </param>
844 /// <param name="state">An object representing data to be used by the continuation action.</param>
845 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new continuation task.</param>
846 /// <param name="continuationOptions">
847 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
848 /// as <see
849 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
850 /// well as execution options, such as <see
851 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
852 /// </param>
853 /// <param name="scheduler">
854 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
855 /// execution.
856 /// </param>
857 /// <returns>A new continuation <see cref="Task"/>.</returns>
858 /// <remarks>
859 /// The returned <see cref="Task"/> will not be scheduled for execution until the current task has
860 /// completed. If the criteria specified through the <paramref name="continuationOptions"/> parameter
861 /// are not met, the continuation task will be canceled instead of scheduled.
862 /// </remarks>
863 /// <exception cref="System.ArgumentNullException">
864 /// The <paramref name="continuationAction"/> argument is null.
865 /// </exception>
866 /// <exception cref="System.ArgumentOutOfRangeException">
867 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
868 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
869 /// </exception>
870 /// <exception cref="System.ArgumentNullException">
871 /// The <paramref name="scheduler"/> argument is null.
872 /// </exception>
873 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
874 /// has already been disposed.
875 /// </exception>
876 public Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state, CancellationToken cancellationToken,
877 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
879 return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
882 // Same as the above overload, only with a stack mark.
883 internal Task ContinueWith(Action<Task<TResult>, object?> continuationAction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken,
884 TaskContinuationOptions continuationOptions)
886 if (continuationAction == null)
888 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationAction);
891 if (scheduler == null)
893 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
896 TaskCreationOptions creationOptions;
897 InternalTaskOptions internalOptions;
898 CreationOptionsFromContinuationOptions(
899 continuationOptions,
900 out creationOptions,
901 out internalOptions);
903 Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
904 this, continuationAction, state,
905 creationOptions, internalOptions
908 // Register the continuation. If synchronous execution is requested, this may
909 // actually invoke the continuation before returning.
910 ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
912 return continuationTask;
915 #endregion
917 #region Func<Task<TResult>,TNewResult> continuations
919 /// <summary>
920 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
921 /// </summary>
922 /// <typeparam name="TNewResult">
923 /// The type of the result produced by the continuation.
924 /// </typeparam>
925 /// <param name="continuationFunction">
926 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
927 /// passed the completed task as an argument.
928 /// </param>
929 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
930 /// <remarks>
931 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
932 /// task has completed, whether it completes due to running to completion successfully, faulting due
933 /// to an unhandled exception, or exiting out early due to being canceled.
934 /// </remarks>
935 /// <exception cref="System.ArgumentNullException">
936 /// The <paramref name="continuationFunction"/> argument is null.
937 /// </exception>
938 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction)
940 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default, TaskContinuationOptions.None);
944 /// <summary>
945 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
946 /// </summary>
947 /// <typeparam name="TNewResult">
948 /// The type of the result produced by the continuation.
949 /// </typeparam>
950 /// <param name="continuationFunction">
951 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
952 /// passed the completed task as an argument.
953 /// </param>
954 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
955 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
956 /// <remarks>
957 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
958 /// task has completed, whether it completes due to running to completion successfully, faulting due
959 /// to an unhandled exception, or exiting out early due to being canceled.
960 /// </remarks>
961 /// <exception cref="System.ArgumentNullException">
962 /// The <paramref name="continuationFunction"/> argument is null.
963 /// </exception>
964 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
965 /// has already been disposed.
966 /// </exception>
967 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken)
969 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
972 /// <summary>
973 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
974 /// </summary>
975 /// <typeparam name="TNewResult">
976 /// The type of the result produced by the continuation.
977 /// </typeparam>
978 /// <param name="continuationFunction">
979 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
980 /// passed the completed task as an argument.
981 /// </param>
982 /// <param name="scheduler">
983 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
984 /// </param>
985 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
986 /// <remarks>
987 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
988 /// completed, whether it completes due to running to completion successfully, faulting due to an
989 /// unhandled exception, or exiting out early due to being canceled.
990 /// </remarks>
991 /// <exception cref="System.ArgumentNullException">
992 /// The <paramref name="continuationFunction"/> argument is null.
993 /// </exception>
994 /// <exception cref="System.ArgumentNullException">
995 /// The <paramref name="scheduler"/> argument is null.
996 /// </exception>
997 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler)
999 return ContinueWith<TNewResult>(continuationFunction, scheduler, default, TaskContinuationOptions.None);
1002 /// <summary>
1003 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1004 /// </summary>
1005 /// <typeparam name="TNewResult">
1006 /// The type of the result produced by the continuation.
1007 /// </typeparam>
1008 /// <param name="continuationFunction">
1009 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1010 /// passed the completed task as an argument.
1011 /// </param>
1012 /// <param name="continuationOptions">
1013 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1014 /// as <see
1015 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1016 /// well as execution options, such as <see
1017 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1018 /// </param>
1019 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1020 /// <remarks>
1021 /// <para>
1022 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1023 /// task has completed, whether it completes due to running to completion successfully, faulting due
1024 /// to an unhandled exception, or exiting out early due to being canceled.
1025 /// </para>
1026 /// <para>
1027 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1028 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1029 /// from the ContinueWith call.
1030 /// </para>
1031 /// </remarks>
1032 /// <exception cref="System.ArgumentNullException">
1033 /// The <paramref name="continuationFunction"/> argument is null.
1034 /// </exception>
1035 /// <exception cref="System.ArgumentOutOfRangeException">
1036 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1037 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1038 /// </exception>
1039 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions)
1041 return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default, continuationOptions);
1044 /// <summary>
1045 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1046 /// </summary>
1047 /// <typeparam name="TNewResult">
1048 /// The type of the result produced by the continuation.
1049 /// </typeparam>
1050 /// <param name="continuationFunction">
1051 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be passed as
1052 /// an argument this completed task.
1053 /// </param>
1054 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1055 /// <param name="continuationOptions">
1056 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1057 /// as <see
1058 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1059 /// well as execution options, such as <see
1060 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1061 /// </param>
1062 /// <param name="scheduler">
1063 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1064 /// execution.
1065 /// </param>
1066 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1067 /// <remarks>
1068 /// <para>
1069 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1070 /// completed, whether it completes due to running to completion successfully, faulting due to an
1071 /// unhandled exception, or exiting out early due to being canceled.
1072 /// </para>
1073 /// <para>
1074 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1075 /// This task's completion state will be transferred to the task returned from the
1076 /// ContinueWith call.
1077 /// </para>
1078 /// </remarks>
1079 /// <exception cref="System.ArgumentNullException">
1080 /// The <paramref name="continuationFunction"/> argument is null.
1081 /// </exception>
1082 /// <exception cref="System.ArgumentOutOfRangeException">
1083 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1084 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1085 /// </exception>
1086 /// <exception cref="System.ArgumentNullException">
1087 /// The <paramref name="scheduler"/> argument is null.
1088 /// </exception>
1089 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1090 /// has already been disposed.
1091 /// </exception>
1092 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken,
1093 TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1095 return ContinueWith<TNewResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
1098 // Same as the above overload, just with a stack mark.
1099 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler,
1100 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
1102 if (continuationFunction == null)
1104 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
1107 if (scheduler == null)
1109 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1112 TaskCreationOptions creationOptions;
1113 InternalTaskOptions internalOptions;
1114 CreationOptionsFromContinuationOptions(
1115 continuationOptions,
1116 out creationOptions,
1117 out internalOptions);
1119 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
1120 this, continuationFunction, null,
1121 creationOptions, internalOptions
1124 // Register the continuation. If synchronous execution is requested, this may
1125 // actually invoke the continuation before returning.
1126 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1128 return continuationFuture;
1130 #endregion
1132 #region Func<Task<TResult>, Object,TNewResult> continuations
1134 /// <summary>
1135 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1136 /// </summary>
1137 /// <typeparam name="TNewResult">
1138 /// The type of the result produced by the continuation.
1139 /// </typeparam>
1140 /// <param name="continuationFunction">
1141 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1142 /// passed the completed task and the caller-supplied state object as arguments.
1143 /// </param>
1144 /// <param name="state">An object representing data to be used by the continuation function.</param>
1145 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1146 /// <remarks>
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.
1150 /// </remarks>
1151 /// <exception cref="System.ArgumentNullException">
1152 /// The <paramref name="continuationFunction"/> argument is null.
1153 /// </exception>
1154 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state)
1156 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default, TaskContinuationOptions.None);
1160 /// <summary>
1161 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1162 /// </summary>
1163 /// <typeparam name="TNewResult">
1164 /// The type of the result produced by the continuation.
1165 /// </typeparam>
1166 /// <param name="continuationFunction">
1167 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1168 /// passed the completed task and the caller-supplied state object as arguments.
1169 /// </param>
1170 /// <param name="state">An object representing data to be used by the continuation function.</param>
1171 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1172 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1173 /// <remarks>
1174 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1175 /// task has completed, whether it completes due to running to completion successfully, faulting due
1176 /// to an unhandled exception, or exiting out early due to being canceled.
1177 /// </remarks>
1178 /// <exception cref="System.ArgumentNullException">
1179 /// The <paramref name="continuationFunction"/> argument is null.
1180 /// </exception>
1181 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1182 /// has already been disposed.
1183 /// </exception>
1184 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state,
1185 CancellationToken cancellationToken)
1187 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
1190 /// <summary>
1191 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1192 /// </summary>
1193 /// <typeparam name="TNewResult">
1194 /// The type of the result produced by the continuation.
1195 /// </typeparam>
1196 /// <param name="continuationFunction">
1197 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1198 /// passed the completed task and the caller-supplied state object as arguments.
1199 /// </param>
1200 /// <param name="state">An object representing data to be used by the continuation function.</param>
1201 /// <param name="scheduler">
1202 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its execution.
1203 /// </param>
1204 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1205 /// <remarks>
1206 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1207 /// completed, whether it completes due to running to completion successfully, faulting due to an
1208 /// unhandled exception, or exiting out early due to being canceled.
1209 /// </remarks>
1210 /// <exception cref="System.ArgumentNullException">
1211 /// The <paramref name="continuationFunction"/> argument is null.
1212 /// </exception>
1213 /// <exception cref="System.ArgumentNullException">
1214 /// The <paramref name="scheduler"/> argument is null.
1215 /// </exception>
1216 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state,
1217 TaskScheduler scheduler)
1219 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, default, TaskContinuationOptions.None);
1222 /// <summary>
1223 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1224 /// </summary>
1225 /// <typeparam name="TNewResult">
1226 /// The type of the result produced by the continuation.
1227 /// </typeparam>
1228 /// <param name="continuationFunction">
1229 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1230 /// passed the completed task and the caller-supplied state object as arguments.
1231 /// </param>
1232 /// <param name="state">An object representing data to be used by the continuation function.</param>
1233 /// <param name="continuationOptions">
1234 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1235 /// as <see
1236 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1237 /// well as execution options, such as <see
1238 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1239 /// </param>
1240 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1241 /// <remarks>
1242 /// <para>
1243 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current
1244 /// task has completed, whether it completes due to running to completion successfully, faulting due
1245 /// to an unhandled exception, or exiting out early due to being canceled.
1246 /// </para>
1247 /// <para>
1248 /// The <paramref name="continuationFunction"/>, when executed, should return a <see
1249 /// cref="Task{TNewResult}"/>. This task's completion state will be transferred to the task returned
1250 /// from the ContinueWith call.
1251 /// </para>
1252 /// </remarks>
1253 /// <exception cref="System.ArgumentNullException">
1254 /// The <paramref name="continuationFunction"/> argument is null.
1255 /// </exception>
1256 /// <exception cref="System.ArgumentOutOfRangeException">
1257 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1258 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1259 /// </exception>
1260 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state,
1261 TaskContinuationOptions continuationOptions)
1263 return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default, continuationOptions);
1266 /// <summary>
1267 /// Creates a continuation that executes when the target <see cref="Task{TResult}"/> completes.
1268 /// </summary>
1269 /// <typeparam name="TNewResult">
1270 /// The type of the result produced by the continuation.
1271 /// </typeparam>
1272 /// <param name="continuationFunction">
1273 /// A function to run when the <see cref="Task{TResult}"/> completes. When run, the delegate will be
1274 /// passed the completed task and the caller-supplied state object as arguments.
1275 /// </param>
1276 /// <param name="state">An object representing data to be used by the continuation function.</param>
1277 /// <param name="cancellationToken">The <see cref="CancellationToken"/> that will be assigned to the new task.</param>
1278 /// <param name="continuationOptions">
1279 /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such
1280 /// as <see
1281 /// cref="System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled">OnlyOnCanceled</see>, as
1282 /// well as execution options, such as <see
1283 /// cref="System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously">ExecuteSynchronously</see>.
1284 /// </param>
1285 /// <param name="scheduler">
1286 /// The <see cref="TaskScheduler"/> to associate with the continuation task and to use for its
1287 /// execution.
1288 /// </param>
1289 /// <returns>A new continuation <see cref="Task{TNewResult}"/>.</returns>
1290 /// <remarks>
1291 /// <para>
1292 /// The returned <see cref="Task{TNewResult}"/> will not be scheduled for execution until the current task has
1293 /// completed, whether it completes due to running to completion successfully, faulting due to an
1294 /// unhandled exception, or exiting out early due to being canceled.
1295 /// </para>
1296 /// <para>
1297 /// The <paramref name="continuationFunction"/>, when executed, should return a <see cref="Task{TNewResult}"/>.
1298 /// This task's completion state will be transferred to the task returned from the
1299 /// ContinueWith call.
1300 /// </para>
1301 /// </remarks>
1302 /// <exception cref="System.ArgumentNullException">
1303 /// The <paramref name="continuationFunction"/> argument is null.
1304 /// </exception>
1305 /// <exception cref="System.ArgumentOutOfRangeException">
1306 /// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
1307 /// cref="System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
1308 /// </exception>
1309 /// <exception cref="System.ArgumentNullException">
1310 /// The <paramref name="scheduler"/> argument is null.
1311 /// </exception>
1312 /// <exception cref="System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
1313 /// has already been disposed.
1314 /// </exception>
1315 public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state,
1316 CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
1318 return ContinueWith<TNewResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
1321 // Same as the above overload, just with a stack mark.
1322 internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, object?, TNewResult> continuationFunction, object? state,
1323 TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
1325 if (continuationFunction == null)
1327 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
1330 if (scheduler == null)
1332 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
1335 TaskCreationOptions creationOptions;
1336 InternalTaskOptions internalOptions;
1337 CreationOptionsFromContinuationOptions(
1338 continuationOptions,
1339 out creationOptions,
1340 out internalOptions);
1342 Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
1343 this, continuationFunction, state,
1344 creationOptions, internalOptions
1347 // Register the continuation. If synchronous execution is requested, this may
1348 // actually invoke the continuation before returning.
1349 ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
1351 return continuationFuture;
1354 #endregion
1356 #endregion
1359 // Proxy class for better debugging experience
1360 internal class SystemThreadingTasks_FutureDebugView<TResult>
1362 private readonly Task<TResult> m_task;
1364 public SystemThreadingTasks_FutureDebugView(Task<TResult> task)
1366 Debug.Assert(task != null);
1367 m_task = task;
1370 [MaybeNull] public TResult Result => m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default!;
1371 public object? AsyncState => m_task.AsyncState;
1372 public TaskCreationOptions CreationOptions => m_task.CreationOptions;
1373 public Exception? Exception => m_task.Exception;
1374 public int Id => m_task.Id;
1375 public bool CancellationPending => (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested;
1376 public TaskStatus Status => m_task.Status;