CSharp 10 Features

Last Updated: 4/27/2022

AsyncMethodBuilderAttribute

  • From C# 7 you can build your own task-like types.
  • You add the System.Runtime.CompilerServices.AsyncMethodBuilderAttribute attribute to a type that can be an async return type.
  • The attribute specifies the type of the associated builder that builds the async method implementation when the specified type is returned from an async method.
  • The custom task type should have GetAwaiter method and the object returned should implement the System.Runtime.CompilerServices.ICriticalNotifyCompletion interface.

CustomTaskAwaiter

public struct CustomTaskAwaiter : INotifyCompletion
{
    public void GetResult() { }
 
    public bool IsCompleted => true;
 
    public void OnCompleted(Action continuation) { }
}

CustomTaskMethodBuilder

public sealed class CustomTaskMethodBuilder
{
    public CustomTaskMethodBuilder()
        => Console.WriteLine("constructor");

    public static CustomTaskMethodBuilder Create()
        => new CustomTaskMethodBuilder();

    public void SetResult() => Console.WriteLine("SetResult");

    public void Start<TStateMachine>(ref TStateMachine stateMachine)
        where TStateMachine : IAsyncStateMachine
    {
        Console.WriteLine("Start task");
        stateMachine.MoveNext();
    }

    public CustomTask Task => default(CustomTask);

    public void AwaitOnCompleted<TAwaiter, TStateMachine>(
        ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : INotifyCompletion
        where TStateMachine : IAsyncStateMachine
    { }

    public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
        ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : ICriticalNotifyCompletion
        where TStateMachine : IAsyncStateMachine
    { }

    public void SetException(Exception e) { }

    public void SetStateMachine(IAsyncStateMachine stateMachine) { }
}

CustomTask

[System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(CustomTaskMethodBuilder))]
public struct CustomTask
{
    public CustomTaskAwaiter GetAwaiter() => default(CustomTaskAwaiter);
}

Async Method

public static async CustomTask RunAsync()
{
	await Task.Yield();
	await default(CustomTask);
}

Apply to Async Method

  • From C# 10, the AsyncMethodBuilder attribute can be applied to an async method to override the builder for that type.
[System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(CustomTaskMethodBuilder))]
public static async CustomTask RunAsync()
{
	await Task.Yield();
	await default(CustomTask);
}

Example

References