我们可以将异步方法变成表达式主体吗?

Can we turn async methods into expression body?

我正在阅读 this 关于 C# 6.0 中的 Expression Bodied Members 的文章,作者演示了这段代码:

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

他说不建议在上面的代码中使用asyncawait关键字:

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();

我想了解更多相关信息。

制作异步方法允许您在其中使用 await。您实际上并不需要等待,因为您没有使用 return 值,并且在该操作完成后您没有做任何事情。在这种情况下,您可以直接 return 任务。这样你的调用者就可以等待内部异步方法,而不会在两者之间产生方法的开销。

这避免了使 ReadFromWeb 成为异步方法的工作。这没什么大不了的,但在这种情况下,你所拥有的只是一次调用,这样做是非常无害的。

让我们看看作者在说什么。当您将方法标记为 async 时,编译器会代表您生成一个状态机,以允许异步执行方式 "feel like" 它正在同步执行。

当你写:

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

编译器生成:

[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;
}

由于您使用的是 Expression Bodied 方法,因此您实际上只有一个方法的衬里。你通常什么时候 await 做某事?当你想操纵异步方法的return值时。使用单线,情况永远不会如此。这意味着您可以在调用级别保存状态机生成,并且只让那些想要 await 调用者堆栈更高层的结果到您的方法上的 await 。这将有效地将您的方法转换为如下所示:

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

这为您节省了编译器分配的已经很苗条状态机struct,这在您创建 EBM 时实际上是非常多余的。