TaskContinuationOptions
While ContinueWith allows us to chain tasks, it often executes blindly—running regardless of whether the previous task succeeded, failed, or was canceled. To build robust asynchronous pipelines, we need surgical control over when and how these continuations run. This is achieved through the TaskContinuationOptions enum.
TaskContinuationOptions provides a set of flags that tell the Task Scheduler how to handle the continuation task. These options can be broadly categorized into conditional execution, scheduling behavior, and hierarchy management.
1. Conditional Execution Options
These are the most frequently used options. They allow you to create "branching" logic in your task chains, where different tasks run based on the final state of the antecedent.
Example: Handling Success, Failure, and Cancellation
In this example, we use a CancellationToken to simulate various outcomes and show how specific continuations respond.
2. Scheduling and Performance Options
These options influence the Task Scheduler's behavior regarding thread allocation and timing.
ExecuteSynchronously: Hints that the continuation should run on the same thread that completed the antecedent. This reduces context switching for very short-lived tasks.LongRunning: Tells the scheduler to potentially allocate a dedicated thread rather than a ThreadPool thread. Use this for tasks that block for long periods (like I/O or infinite loops).PreferFairness: Requests the scheduler to schedule tasks in the order they were queued, rather than using internal optimizations that might favor efficiency over order.
Example: Synchronous vs. Long Running
3. Hierarchy and Relationship Options
TPL allows tasks to have parent-child relationships. These options control how continuations interact with that hierarchy.
AttachedToParent: If the antecedent is a child task, this continuation will also be attached to the parent. The parent task will not complete until all attached children and their continuations are done.DenyChildAttach: Prevents any tasks created within the continuation from being attached as children.
Example: AttachedToParent
Summary Table: Key Options
| Option | Category | Effect |
OnlyOnRanToCompletion | Conditional | Executes only if the antecedent finishes successfully. |
NotOnFaulted | Conditional | Executes only if the antecedent did NOT throw an exception. |
ExecuteSynchronously | Scheduling | Runs on the thread that completed the antecedent. |
LongRunning | Scheduling | Requests a dedicated thread for a long-lived task. |
AttachedToParent | Hierarchy | Links the continuation's lifetime to the parent task. |
A Note on Compatibility
It is important to remember that some options are mutually exclusive. For instance, you cannot combine OnlyOnRanToCompletion with NotOnRanToCompletion. Furthermore, as mentioned in the documentation, conditional options are not valid for multi-task continuations (like ContinueWhenAll) because the scheduler wouldn't know which antecedent task's state to check.