Phase 22 of 30 · Topic 22.5

Custom Awaiters & `INotifyCompletion` / `GetAwaiter()` Pattern

1Concept

C# async/await is pattern-based. Any type with a `GetAwaiter()` method returning an object with `IsCompleted`, `OnCompleted(Action)`, and `GetResult()` can be awaited with `await`.

2Architecture Diagram

Type with `public CustomAwaiter GetAwaiter()`
├── bool IsCompleted { get; }
├── void OnCompleted(Action continuation); (INotifyCompletion)
└── T GetResult();
       │
       ▼ Enables `await customObject;` !

3Code Example

C# 13 & .NET 9
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

public struct CustomYieldAwaiter : INotifyCompletion
{
    public bool IsCompleted => false;
    public void OnCompleted(Action continuation) => Task.Run(continuation);
    public void GetResult() { }
}

public class CustomAwaitable
{
    public CustomYieldAwaiter GetAwaiter() => new();
}

public class CustomAwaiterDemo
{
    public static async Task Main()
    {
        var custom = new CustomAwaitable();
        await custom; // Pattern-based custom awaiter!
        Console.WriteLine("Resumed from custom awaiter execution.");
    }
}

4Expected Output

Resumed from custom awaiter execution.

5Key Takeaways

  • C# await does not require inheriting from Task; it relies on the `GetAwaiter` pattern.
  • Powers unity game engine awaiters (`await new WaitForSeconds(1.0f)`).
  • Enables custom high-speed fiber and actor scheduling.