在C#5.0 In A Nutshell,第590页,给出了以下示例:
async void ButtonClick (object sender, RoutedEventArgs args)
{
await Task.Delay(1000);
throw new Exception ("Will this be ignored?");
}
本书指出不会捕获异常,因为该函数将立即返回到await行的消息循环,并且当一秒钟之后抛出异常时,它将不会被消息中的try / catch捕获循环。
本书继续说明AsyncVoidMethodBuilder必须将延续封装在另一个函数中,以便它可以构建另一个try / catch块,并将任何捕获的异常转发到同步上下文(如果存在)。
这让我感到困惑,因为我认为,因为从GUI线程调用Task.Delay,同步化上下文的存在将导致Task.Delay的继续在GUI线程上执行。我原以为它可以因此直接从try / catch子句中的消息循环继续执行,并且仍然被捕获而无需封装在另一个函数中。
我错过了什么?
答案 0 :(得分:4)
你的理解是正确的;该异常将直接在UI SynchronizationContext
上重新引发,并被消息循环捕获。从那里它将传递给UI应用程序范围的处理程序。
本书实际上说的是在async
方法返回后无法捕获异常,这就是AsyncVoidMethodBuilder
将在适当的SynchronizationContext
上重新引发异常的原因。
这很重要,因为async void
方法可能会“留下”其UI上下文,例如,使用ConfigureAwait(false)
。但是如果在该点之后发生异常,它必须重新同步到原始SynchronizationContext
,而不一定是抛出异常时的上下文。