捕获异步操作的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
,但它在处理exception的方式上有所不同。 await
会抛出实际的exception(例如WebException
),而Task
会抛出一个包含实际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。 您可以通过访问返回的Task
的Task.Result
属性来执行相同的Task.Result
因为Task.WhenAny
返回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]; } }