捕获异步操作的异常
本文关键字:异常 异步操作 | 更新日期: 2023-09-27 18:20:16
我在这里阅读了更多关于异步的信息: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);
第一个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;
}
}
}
显然,等待任务更简单,因此建议使用此方法从任务中检索结果
此处await
的使用创建了所需的错误处理语义。如果他使用Result
而不是await
,则AggregateException
将被直接重新抛出;当使用await
时,AggregateException
中的第一个异常被拉出,异常被重新抛出。清除此代码的作者希望抛出WebException
,而不是需要手动打开的AggregateException
。
他肯定会用另一种方法吗。这只是代码作者喜欢的方法,因为它允许他编写更像传统同步代码的代码,而不是从根本上改变代码的风格。
你说得对。没有必要。你可以用代替它
if (recommendation.Result)
BuyStock(symbol);
还要注意,当给出已完成的任务时,await
将不会等待(不会设置继续)。在这种情况下,它将作为优化同步执行。我想作者利用了这种优化。
若你们问作者为什么这样写,可能是一致性?只有他知道!。
如果我已经这样做了:任务推荐=等待任务。WhenAny(推荐);为什么这样做:如果(等待推荐)买入股票(符号);
因为Task.WhenAny
返回一个Task<Task<bool>>
,并且您希望打开输出Task
以检索结果布尔。您可以通过访问返回的Task
的Task.Result
属性来执行同样的操作
其他答案指出,您必须await
await Task.WhenAll
返回的任务才能打开返回值(或者,您可以使用Result
属性)。
然而,你也可以摆脱你的try/catch(避免捕获不必要的异常是一件好事)
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];
}
}
因为Task.WhenAny<TResult>(IEnumerable<Task<TResult>> tasks)
返回一个Task<Task<TResult>>
。外部任务(由Task.WhenAny
调用创建的任务)将在传递给它的任何任务完成时完成,从而完成任务。