我们能将异步方法转换为表达式体吗?

4

我正在阅读关于C# 6.0中的表达式体成员的这篇文章,作者演示了以下代码:

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

他说在上面的代码中不建议使用asyncawait关键字:
编译器为实现该方法的异步状态机进行了一些复杂的操作。由于该方法结构的特殊性,这些额外的工作并没有实现太多效果。它创建了一个状态机来包装从另一个方法返回的任务的任务的简单解包装。 他建议我们不使用asyncawait来编写代码:
public Task<string> ReadFromWebSimple() => RunWebRequest();

我想了解更多关于这个的信息。

2个回答

9
让我们来看看作者在谈论什么。当你将一个方法标记为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
使一个方法异步允许你在其中使用await。如果你不需要使用返回值并且在操作完成后也没有其他事情要做,那么你实际上不需要await。在这种情况下,你可以直接返回任务。这样,你的调用者就可以等待内部异步方法而无需中间方法的开销。
这避免了将ReadFromWeb变成异步方法所需的工作。虽然这不是什么大问题,但在这种只有单个调用的情况下,这样做是相当无害的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接