捕获异步操作的exception

我正在阅读更多关于异步的内容: http : //msdn.microsoft.com/en-us/library/hh873173( v = vs1010) .aspx

通过这个例子:

Task [] recommendations = …; while(recommendations.Count > 0) { Task recommendation = await Task.WhenAny(recommendations); try { if (await recommendation) BuyStock(symbol); break; } catch(WebException exc) { recommendations.Remove(recommendation); } } 

我想知道,如果我已经在Task.WhenAny上执行等待,为什么我需要在try块内再次等待?

如果我已经这样做了: Task recommendation = await Task.WhenAny(recommendations); 为什么这样: if (await recommendation) BuyStock(symbol);

第一个await存在异步等待第一个任务完成(即recommendation )。 第二个await仅用于从已完成的任务中提取实际结果,并抛出存储在任务中的exception。 ( 重要的是要记住,等待已完成的任务已经过优化并将同步执行 )。

获得结果的另一个选项是使用Task.Result ,但它在处理exception的方式上有所不同。 await会抛出实际的exception(例如WebException ),而Task.Result会抛出一个包含实际exception的AggregateException

 Task [] recommendations = …; while(recommendations.Count > 0) { Task recommendation = await Task.WhenAny(recommendations); try { if (recommendation.Result) { BuyStock(symbol); } break; } catch(AggregateException exc) { exc = exc.Flatten(); if (exc.InnerExceptions[0] is WebException) { recommendations.Remove(recommendation); } else { throw; } } } 

显然等待任务更简单,因此这是从任务中检索结果的推荐方法。

await这里使用await会创建所需的error handling语义。 如果他使用Result而不是await那么将直接重新抛出AggregateException ; 当使用await ,会抛出AggregateException的第一个exception,并重新抛出exception。 清除此代码的作者需要抛出WebException ,而不是他需要手动解包的AggregateException

当然,他可以使用另一种方法吗? 这只是代码作者首选的方法,因为它允许他更像传统的同步代码编写代码,而不是从根本上改变代码的样式。

你是对的。 没有必要。 你可以用它替换它

 if (recommendation.Result) BuyStock(symbol); 

另请注意,在完成任务时, await将不会等待(不会设置延续)。 它将在这种情况下作为优化同步执行。 我想作者会利用这种优化。

如果你问为什么作者这样写,可能是一致性? 只有他知道!

如果我已经这样做了:任务建议= await Task.WhenAny(推荐); 为什么这样:if(等待推荐)BuyStock(symbol);

因为Task.WhenAny返回一个Task>并且您想要打开outter Task以检索生成的bool。 您可以通过访问返回的TaskTask.Result属性来执行相同的Task.Result

因为Task.WhenAny(IEnumerable> tasks)返回Task> 。 外部任务(由Task.WhenAny调用创建的任务)将在传递给它的任何任务以完成的任务结束时完成。

其他答案指出,您必须await await Task.WhenAll返回的任务来解包返回值(或者,您可以使用Result属性)。

但是,你也可以摆脱你的try / catch(避免捕获不必要的exception是一件好事)

 Task recommendation = await Task.WhenAny(recommendations); if(!recommendation.IsFaulted) { if (await recommendation) BuyStock(symbol); break; } else { if(recommendation.Exception.InnerExceptions[0] is WebException) { recommendations.Remove(recommendation); } else { throw recommendation.Exception.InnerExceptions[0]; } }