Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 等待最后一个异步调用和仅仅返回它之间有区别吗?_C#_Async Await - Fatal编程技术网

C# 等待最后一个异步调用和仅仅返回它之间有区别吗?

C# 等待最后一个异步调用和仅仅返回它之间有区别吗?,c#,async-await,C#,Async Await,见问题标题 换句话说,给定一种方法 async Task FrobnicateAsync() { ... } 两者之间有什么(可能是细微的)区别吗 async Task FrobAndFrobnicateAsync() { Frob(); await FrobnicateAsync(); } 及 如果您逐字地显示了代码,那么您应该更喜欢return FrobnicateAsync()版本-它避免了额外的状态机抽象层,而且效率更高 如果您有其他内容,特别是围绕返回的任何最终(包

见问题标题

换句话说,给定一种方法

async Task FrobnicateAsync() { ... }
两者之间有什么(可能是细微的)区别吗

async Task FrobAndFrobnicateAsync()
{
    Frob();
    await FrobnicateAsync();
}


如果您逐字地显示了代码,那么您应该更喜欢
return FrobnicateAsync()
版本-它避免了额外的状态机抽象层,而且效率更高

如果您有其他内容,特别是围绕
返回
的任何
最终
(包括
使用
)代码,则必须确保使用
等待
版本,以便在
异步
任务完成后才发生
最终
代码

如果有疑问,请使用
async
/
wait
版本

好消息是:在它们之间切换不会影响签名(因此不是一个突破性的更改),因此您现在可以更有效地实现它,如果您发现以后需要使用块添加一个
,则可以更改为
异步
/
等待

另外一个想法是:如果您通常希望同步完成,那么您可以更微妙:

Task FrobAndFrobnicateAsync()
{
    async Task Awaited(Task t) => await t;
    Frob();
    var task = FrobnicateAsync();
    // in .NET vFuture there will be a task.IsCompletedSuccessfully
    return task.State == TaskState.RanToCompletion ? task : Awaited(task);    
}
这避免了在不需要时使用状态机

我有一篇博客文章

由于在
等待
之前有一个非常重要的
Frob
,因此我建议您保持
异步
等待
。这种方法的好处是:

  • 如果没有
    async
    Frob
    抛出异常,那么将直接抛出异常,这对于消费者来说是一种令人惊讶的行为。即使Frob今天没有抛出异常,它也可以在明年抛出异常;因此,带有
    wait
    的代码更易于维护
  • 如果没有
    async
    ,则
    Frob
    FrobnicateAsync
    在同一逻辑调用上下文中不存在(假设它实际上是
    async
    );相反,它将与
    frobandfrobniteasync
    的调用者存在于相同的逻辑调用上下文中。在大多数代码中,这不是一个问题

另请参见比尔·瓦格纳(Bill Wagner)昨天写的一篇文章,其中有一个潜在差异的例子。另请参见:我不确定我是否总是同意这一点-如果
Frob
可能抛出异常,那么使其异步就有很大的不同。请看斯蒂芬·克利里(Stephen Cleary)关于这一点的博文:(在某些情况下,我认为这很好,在另一些情况下,没有那么多。)@JonSkeet,但你没有吸收其中的差异;调用者仍然应该是
等待
-ing或其他什么,因此他们将以通常的方式在那里获得异常,但这可能在他们的代码中处于完全不同的点。如果这是一个“调用方代码中的错误”异常(例如验证),那么我对此没有意见-如果它类似于一个
IOException
,那么更改抛出它的点感觉更像是一个突破性的更改。@JonSkeet啊,你是说调用
FrobnicateAsync
之前
FrobnicateAsync
中的异常?同意:这绝对是一个区别;讨论哪个版本(如果有的话)更正确是一个非常复杂的对话。就我个人而言,无论是哪种方式,我都可以接受。另一方面,在应用程序代码中,您更有可能了解调用者,并且能够在必要时改变他们对异常的期望:)
Task FrobAndFrobnicateAsync()
{
    async Task Awaited(Task t) => await t;
    Frob();
    var task = FrobnicateAsync();
    // in .NET vFuture there will be a task.IsCompletedSuccessfully
    return task.State == TaskState.RanToCompletion ? task : Awaited(task);    
}