我正在阅读有关异步的更多内容:http://msdn.microsoft.com/en-us/library/hh873173(v=vs.110).aspx
通过这个例子:
Task<bool> [] recommendations = …;
while(recommendations.Count > 0)
{
Task<bool> recommendation = await Task.WhenAny(recommendations);
try
{
if (await recommendation) BuyStock(symbol);
break;
}
catch(WebException exc)
{
recommendations.Remove(recommendation);
}
}
我想知道,如果我已经在Task.WhenAny
执行等待,为什么我需要在try块内再次等待?
如果我已经这样做了:Task<bool> recommendation = await Task.WhenAny(recommendations);
为什么这样做:if (await recommendation) BuyStock(symbol);
答案 0 :(得分:8)
第一个await
存在异步等待第一个任务完成(即recommendation
)。
第二个await
仅用于从已完成的任务中提取实际结果,并抛出存储在任务中的异常。 (重要的是要记住等待已完成的任务已经过优化并将同步执行)。
获取结果的另一个选项是使用Task<T>.Result
,但它处理异常的方式不同。 await
会抛出实际的异常(例如WebException
),而Task<T>.Result
会抛出包含实际异常的AggregateException
。
Task<bool> [] recommendations = …;
while(recommendations.Count > 0)
{
Task<bool> 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;
}
}
}
显然等待任务更简单,因此这是从任务中检索结果的推荐方法。
答案 1 :(得分:5)
此处await
的使用创建了所需的错误处理语义。如果他使用Result
代替await
,那么AggregateException
将直接重新投放;使用await
时,AggregateException
中的第一个异常会被拉出,重新抛出异常。清除此代码的作者需要抛出WebException
,而不是他需要手动解包的AggregateException
。
他确实可以使用其他方法吗?这只是代码作者首选的方法,因为它允许他更像传统的同步代码编写代码,而不是从根本上改变代码的风格。
答案 2 :(得分:4)
你是对的。没有必要。您可以用
替换它if (recommendation.Result)
BuyStock(symbol);
另请注意,await
在完成任务时不会等待(不会设置继续)。它将在这种情况下作为优化同步执行。我想作者会利用这种优化。
如果你问为什么作者这样写,可能是一致性?只有他知道!。
答案 3 :(得分:1)
如果我已经这样做了:任务建议= await Task.WhenAny(推荐);为什么这样做:if(等待推荐)BuyStock(symbol);
因为Task.WhenAny
返回Task<Task<bool>>
,并且您想要解包外部Task
以检索生成的bool。您可以通过访问返回的Task.Result
Task
属性来执行相同操作
答案 4 :(得分:1)
其他答案指出,您必须await
await Task.WhenAll
返回的任务才能解包返回值(或者,您可以使用Result
属性)。
但是,你也可以摆脱你的尝试/捕获(这是一件好事,以避免捕获不必要的异常)
Task<bool> 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];
}
}
答案 5 :(得分:0)
因为Task.WhenAny<TResult>(IEnumerable<Task<TResult>> tasks)
会返回Task<Task<TResult>>
。外部任务(由Task.WhenAny
调用创建的任务)将在传递给它的任何任务完成时完成,结果是完成的任务。