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 theSystem.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
- https://devblogs.microsoft.com/premier-developer/dissecting-the-async-methods-in-c/
- https://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs,b07562c618ee846c
- https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#asyncmethodbuilder-attribute