Course contentsShow
← C#
Lesson 98 of 1,9081. C# Language FoundationsFree lesson

Custom Async Method Builders

Control the execution flow of asynchronous methods for specific environments.

In this lesson, you will learn how to take total control over how asynchronous methods execute by creating your own "engine" for async tasks.

The Problem: One Size Doesn't Fit All

Normally, when you mark a method as async, C# uses the standard AsyncTaskMethodBuilder under the hood. This builder knows how to create Task or ValueTask objects and manage their state machines. However, if you are building a high-performance system—like a game engine or a custom networking framework—you might not want the overhead of allocating standard Task objects. You might want to run tasks on a specialized thread pool or use a custom data structure to track completion.

The Solution: Custom Builders

A Custom Async Method Builder is a class that tells the compiler: "Don't use the default task machinery; use my logic instead."

You instruct the compiler to use your custom builder by applying the [AsyncMethodBuilder(typeof(MyCustomBuilder))] attribute to your custom return type (like a custom MyCustomTask struct). Once you do this, the C# compiler intercepts the async state machine and routes all its operations—like AwaitOnCompleted or SetResult—through your builder.

A Conceptual Sketch

Think of the default builder as a standard delivery truck. A custom builder is you building your own bicycle to deliver the package instead, perhaps because it's faster or fits down a narrower alley.

[AsyncMethodBuilder(typeof(MyCustomBuilder))]
public struct MyCustomTask { /* ... */ }

public struct MyCustomBuilder
{
    // The compiler calls these methods to drive the state machine
    public static MyCustomBuilder Create() => new MyCustomBuilder();
    public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { /* ... */ }
    public void SetResult() { /* Custom logic to complete the task */ }
    public void SetException(Exception e) { /* Custom error handling */ }
    // ... plus methods for awaiter integration
}

By implementing this builder, you control exactly when the state machine transitions, how memory is allocated for the task, and how execution is scheduled. This is a powerful, low-level tool that allows you to strip away the abstractions of standard Task objects for specific, high-performance environments.

Key Takeaway: A custom async method builder allows you to replace the standard C# task-handling logic with your own implementation, giving you complete authority over the execution, scheduling, and memory allocation of asynchronous methods.