Task.ContinueWith attaches a callback that runs after a Task completes, faults, or is canceled. The callback receives the completed Task, allowing code to inspect its state and, for Task<T>, read its result. section 3.2.2 section 3.2.4
Use the continuation model deliberately:
- Check IsCompletedSuccessfully before consuming a successful result; reading Result before completion blocks, while reading it after a fault or cancellation throws. section 3.2.2 section 3.2.4
- Handle failures through the completed task’s exception; faulted tasks expose an AggregateException containing the original exception in InnerExceptions. section 3.2.4
- Chain continuations only when necessary: each asynchronous step moves logic farther right, reduces readability, and complicates returning results, throwing exceptions, and disposing resources. section 3.2.2 section 3.3
- Remember that a ContinueWith callback runs on the thread pool, not automatically on a UI thread; marshal UI updates with BeginInvoke or Dispatcher.BeginInvoke. section 11.1.1
Reading a file asynchronously
A continuation can process bytes after File.ReadAllBytesAsync completes: `var readCompleted = File.ReadAllBytesAsync("example.bin"); readCompleted.ContinueWith(t => { if (t.IsCompletedSuccessfully) { byte[] bytes = t.Result; /* process bytes */ } });` For multi-step file parsing, equivalent nested continuations require explicit state, cleanup, callbacks, and exception propagation, whereas async/await expresses the same sequence more directly.
Listing 11.3 UI access with ContinueWith
private void button1_Click(object sender, EventArgs ea)
{
var result = DoSomething(textBox1.Text).ContinueWith(t=>
{
label1.BeginInvoke((Action)(()=> #1
{
label1.Text = t.Result));
});
}
}
Inspect the UI-safe continuation pattern that marshals result handling back to the UI thread with BeginInvoke. section 11.1.1
