How does asynchronous Main work under the hood?
C# 7.1 comes with option to use asynchronous Main
method. That means now the Main
can have async
modifier and return Task
or Task<int>
. But how it works under the hood? Let’s find out.
Given this feature is available from C# 7.1 it’s clearly just compiler feature not relying on anything from say CLR. Thus the compiler is doing “just” some transformation.
History
Before C# 7.1 if you wanted to have asynchronous Main
, you has basically two options.
The straightforward using Wait
.
static void Main(string[] args)
{
MainAsync().Wait();
}
Or, if you knew little bit of inner workings, using GetAwaiter
and GetResult
.
static void Main(string[] args)
{
MainAsync().GetAwaiter().GetResult();
}
These two approaches are not exactly the same, in particular concerning exceptions, but both get the job done. Is compiler doing something else? Something smarter?
C# 7.1 version
I created an empty console application, with empty static async Task Main(string[] args)
and added <LangVersion>7.1</LangVersion>
to the csproj
. Opened good old ildasm
and here’s the result.
.method private hidebysig specialname static
void '<Main>'(string[] args) cil managed
{
.entrypoint
// Code size 20 (0x14)
.maxstack 1
.locals init (valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter V_0)
IL_0000: ldarg.0
IL_0001: call class [System.Runtime]System.Threading.Tasks.Task ConsoleApp1.Program::Main(string[])
IL_0006: callvirt instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter [System.Runtime]System.Threading.Tasks.Task::GetAwaiter()
IL_000b: stloc.0
IL_000c: ldloca.s V_0
IL_000e: call instance void [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter::GetResult()
IL_0013: ret
} // end of method Program::'<Main>'
It generated new <Main>(string[] args)
method and the body is simple Program.Main(args).GetAwaiter().GetResult();
. If the Main
returns int
, then the method is basically the same, only having explicit return of value from GetResult
.
Conclusion
There you have it. Nothing special and absolutely straightforward. So even if you can’t use C# 7.1, you can write this yourself without any real effort.