【问题标题】:Can we turn async methods into expression body?我们可以把异步方法变成表达式体吗?
【发布时间】:2015-10-10 12:51:27
【问题描述】:
我正在阅读this关于 C# 6.0 中的表达式主体成员的文章,作者演示了这段代码:
public async Task<string> ReadFromWeb() => await RunWebRequest();
他说不建议在上面的代码中使用async和await关键字:
编译器正在执行一些繁重的工作来实现异步
此方法的状态机。由于方法的结构,
额外的工作并没有真正完成太多。它正在创建一个状态
机器来包装一个任务,该任务只是解开从一个返回的任务
不同的方法。
他建议我们应该编写不带 async 和 await 的代码:
public Task<string> ReadFromWebSimple() => RunWebRequest();
我想了解更多相关信息。
【问题讨论】:
标签:
c#
asynchronous
async-await
c#-6.0
【解决方案1】:
让我们看看作者在说什么。当您将方法标记为 async 时,编译器会代表您生成一个状态机,以便让异步执行方式“感觉”它正在同步执行。
当你写作时:
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;
}
由于您使用的是表达式主体方法,因此您实际上只有一个方法的衬里。您一般什么时候await 做某事?当您想要操作异步方法的返回值时。对于单线,情况绝不会如此。这意味着您可以在调用级别保存状态机生成,并且只让那些想要准确地await 结果的人在调用者堆栈中更高到您方法上的await。这将有效地将您的方法转换为如下所示:
public Task<string> ReadFromWeb()
{
return this.RunWebRequest();
}
这为您节省了编译器分配的相当已经很苗条的状态机struct,这在您创建 EBM 时实际上是相当多余的。
【解决方案2】:
使方法异步允许您在其中使用等待。您真的不需要等待,因为您没有使用返回值,并且在该操作完成后您没有做任何事情。在这种情况下,您可以直接返回任务。这样,您的调用者就可以等待内部异步方法,而不会产生中间方法的开销。
这避免了使 ReadFromWeb 成为异步方法的工作。这没什么大不了的,但在这种情况下,你所拥有的只是一次调用,这样做是无害的。