The bulk of this chapter focused on task-based asynchronous pattern, which features the async/await syntax. It provided detailed examples demonstrating how much simpler it is to leverage TAP rather than to solely rely on TPL, especially when transforming code from a synchronous to an asynchronous implementation. In so doing, it detailed the requirements for the return type of an async method. In summary, the async/await feature makes programming complex workflows with Task objects much easier by automatically rewriting your programs to manage the continuation “wiring” that composes larger tasks out of smaller tasks.
Next, the chapter focused on async streams and the C# 8.0–introduced IAsyncEnumerable<T> data type. It considered how to leverage these capabilities to create asynchronous iterators and how to consume them with async foreach statements.
At this point, readers should have a firm foundation regarding how to write asynchronous code, except for parallel iterations (the topic of Chapter 21) and thread synchronization (which is covered in Chapter 22).