Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we turn async methods into expression body?

I was reading this article about Expression Bodied Members in C# 6.0, the author demonstrated this code:

public async Task<string> ReadFromWeb() => await RunWebRequest();

He says that it's not recommended to use async and await keywords in above code:

The compiler is performing some heavy lifting to implement the async state machine for this method. Because of the structure of the method, that extra work isn't really accomplishing much. It's creating a state machine to wrap a task that simply unwraps a task returned from a different method. He proposed that we should write the code without async and await:

public Task<string> ReadFromWebSimple() => RunWebRequest();

I'd like to know more information about that.

like image 632
Sirwan Afifi Avatar asked Oct 16 '25 06:10

Sirwan Afifi


2 Answers

Lets see what the author was talking about. When you mark a method as async, the compiler generates a state-machine on your behalf in order to allow the asynchronous style of execution to "feel like" it's executing synchronously.

When you write:

public async Task<string> ReadFromWeb() => await RunWebRequest();

The compiler generates:

[AsyncStateMachine(typeof(C.<RunWebRequest>d__1))]
public Task<string> RunWebRequest()
{
    C.<RunWebRequest>d__1 <RunWebRequest>d__;
    <RunWebRequest>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
    <RunWebRequest>d__.<>1__state = -1;
    AsyncTaskMethodBuilder<string> <>t__builder = <RunWebRequest>d__.<>t__builder;
    <>t__builder.Start<C.<RunWebRequest>d__1>(ref <RunWebRequest>d__);
    return <RunWebRequest>d__.<>t__builder.Task;
}

Since you're using an Expression Bodied Method, you actually have a single liner of a method. When do you generally await on something? when you want to manipulate the return value of the async method. With one-liners, that's never the case. This means that you can save the state-machine generation at the invocation level, and let only those who want to acutally await the result higher up the caller stack to await on your method. This will effectively transform your method to look like this:

public Task<string> ReadFromWeb()
{
    return this.RunWebRequest();
}

Which saves you the rather already slim state-machine struct allocated by the compiler, which is actually quite redundant when you're creating an EBM.

like image 180
Yuval Itzchakov Avatar answered Oct 17 '25 21:10

Yuval Itzchakov


Making a method async allows you to use await inside it. You don't really need await as you're not using the return value and you're not doing anything after that operation completes. In this case you can just return the task directly instead. That way your caller awaits the inner async method without the overhead of the method in between.

This avoids the work being done to make ReadFromWeb an async method. It's not a huge deal but in this case where all you have is a single invocation doing that is pretty harmless.

like image 45
i3arnon Avatar answered Oct 17 '25 19:10

i3arnon