I'm reading up more about async here: http://msdn.microsoft.com/en-us/library/hh873173(v=vs.110).aspx
Going through this example:
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);
}
}
I wonder, if I'm already performing await on Task.WhenAny
why do I need to await again inside of the try block?
If I already did this: Task<bool> recommendation = await Task.WhenAny(recommendations);
Why do this: if (await recommendation) BuyStock(symbol);
The use of
await
here creates the desired error handling semantics. If he usedResult
instead ofawait
then theAggregateException
would be rethrown directly; when usingawait
the first exception within theAggregateException
is pulled out an that exception is re-thrown. Clear the author of this code wanted theWebException
to be thrown, rather than anAggregateException
that he would need to manually unwrap.Could he have used another approach, sure. This was simply the approach that the author of the code preferred, as it allows him to write the code more like traditional synchronous code rather than radically changing the style of the code.
Because
Task.WhenAny
returns aTask<Task<bool>>
and you want to unwrap the outterTask
to retrieve the resulting bool. You could do the same by accessing theTask.Result
property of the returnedTask
Because
Task.WhenAny<TResult>(IEnumerable<Task<TResult>> tasks)
returns aTask<Task<TResult>>
. The outer task (the one created by theTask.WhenAny
call) will complete when any of the tasks passed to it completes with the completed task as a result.The first
await
exists to asynchronously wait for the first task to complete (i.e.recommendation
). The secondawait
is only there to extract the actual result out of the already completed task, and throw exceptions stored in the task. (it's important to remember that awaiting a completed task is optimized and will execute synchronously).A different option to get the result would be using
Task<T>.Result
, however it differs in the way it handles exceptions.await
would throw the actual exception (e.gWebException
) whileTask<T>.Result
would throw anAggregateException
containing the actual exception inside.Clearly awaiting the task is simpler and so it's the recommended way of retrieving a result out of a task.
You're right. It is not necessary. You could replace it with
Also note that
await
will not await(will not set continuation) when completed task is given. It will just execute synchronously in that case as a optimization. I guess author leverages that optimization.If you ask why author wrote that way, May be consistency? only he knows!.
Other answers have pointed out that you have to
await
the task returned byawait Task.WhenAll
to unwrap the return value (alternatively, you can use theResult
property).However, you can also get rid of your try/catch (and it's a good thing to avoid catching unnecessary exception)