Using async and await versus simply returning Task

/Peter/Zhwp_Question_Mark.svg.png

Question: what is the difference between this:

public Task NoAsyncAndAwait()
{
  return client.SomeAsyncAPI();
}

and this

public async Task WithAsyncAndAwait()
{
  await client.SomeAsyncAPI();
}

The first method simply returns the inner method, while the second one uses async and await to call the inner method. One could argue that they both will result in the same thing. Which is true, to a certain degree.

But what does the compiler generate?

Let us use dnSpy to look at the generated code (since async and await gets compiled into "simpler" C# we can get a better understanding about what happens behind the screen...

The NoAsyncAndAwait method, after decompiling with dnSpy looks like this:

// TaskVsAwaitTask.AsyncClient
// Token: 0x06000003 RID: 3 RVA: 0x00002068 File Offset: 0x00000268
public Task NoAsyncAndAwait()
{
	return this.client.SomeAsyncAPI();
}

Nothing special here. But the WithAsyncAndAwait method, which uses async and await looks like this:

// TaskVsAwaitTask.AsyncClient
// Token: 0x06000004 RID: 4 RVA: 0x00002088 File Offset: 0x00000288
[DebuggerStepThrough]
public Task WithAsyncAndAwait()
{
	AsyncClient.<WithAsyncAndAwait>d__2 <WithAsyncAndAwait>d__ = new AsyncClient.<WithAsyncAndAwait>d__2();
	<WithAsyncAndAwait>d__.<>4__this = this;
	<WithAsyncAndAwait>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
	<WithAsyncAndAwait>d__.<>1__state = -1;
	<WithAsyncAndAwait>d__.<>t__builder.Start<AsyncClient.<WithAsyncAndAwait>d__2>(ref <WithAsyncAndAwait>d__);
	return <WithAsyncAndAwait>d__.<>t__builder.Task;
}

This method will result in the generation of a AsyncClient.<WithAsyncAndAwait>d__2 class which implements the workflow of this method. So, a lot more code gets generated.

Conclusion: Don't use async and await in this kind of scenario.