C#
Roslyn
async programming
state machines
data structures

Why are async state machines classes and not structs in Roslyn?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

In the .NET ecosystem, the Roslyn compiler plays a crucial role in transforming high-level C# code into intermediate language code. One specific area of interest is how the Roslyn compiler handles asynchronous methods. A key aspect of that process is the use of async state machines. This article dives into why these async state machines are implemented as classes, rather than structs, breaking down technical reasons, challenges, and design decisions.

Understanding Async State Machines

Asynchronous programming in C# uses the async and await keywords to manage asynchronous operations more easily. Underneath the hood, when the Roslyn compiler encounters an asynchronous method, it generates what's known as an "async state machine." This state machine tracks the state of the method across asynchronous calls, thus allowing a method to halt and resume its execution.

How Async State Machines Work

An async state machine in C# typically:

  1. Maintains State: Stores the current state of the method, so it knows where to continue after the await call.
  2. Manages Control Flow: Implements complex flow-control logic to handle various states of asynchronous execution.
  3. Contains Local Variables: Saves any local variables and method parameters needed when execution resumes.

Here's a simplified example of what happens when a method is marked as async:

  • Continuously updates its variables.
  • Transitions across states without incurring the overhead associated with copying the entire structure.
  • Garbage Collection: When the state machine is no longer in use, its memory can be efficiently garbage collected.
  • Reduced Copying: Classes avoid the inefficiencies and potential errors associated with copying entire data structures, which would be required for structs upon any state change.
  • Inheritance Support: Classes support inheritance, which means they can easily implement interfaces like IAsyncStateMachine. This provides additional flexibility in dynamically replacing or overriding specific parts of the state machine logic.
  • Containment of Complex Logic: A state machine may involve intricate logic that deals with state transitions, error handling, and completion tasks, which is more naturally encapsulated within a class boundary.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.