Currently when multiple Tasks are started concurrently and you need the results from all of them to continue, the code can get quite messy. An example:
```c#
var googleTask = GetGoogleDataAsync();
var bingTask = GetBingDataAsync();
var yahooTask = GetYahooDataAsync();
await Task.WhenAll(googleTask, bingTask, yahooTask);
var googleData = await googleTask;
var bingData = await bingTask;
var yahooData = await yahooTask;
// then some logic which uses all data
With some magic from the compiler, and a syntax similar to the value tuple deconstruction, it could get very concise:
```c#
var (googleData, bingData, yahooData) = await (GetGoogleDataAsync(), GetBingDataAsync(), GetYahooDataAsync());
It could even be done without compiler support, if GetAwaiter() was added to ValueTuple.
What do you think about it?
In your first example, having both the Task.WhenAll and the multiple awaits is unnecessary. If you have Task.WhenAll, you know all of the tasks have completed, so you can then access .Result; if you have the multiple awaits, you don't need the Task.WhenAll.
Semantically, then, you can already write var (googleData, bingData, yahooData) = (await GetGoogleDataAsync(), await GetBingDataAsync(), await GetYahooDataAsync()), which is almost the same.
Another possibility would be to allow deconstructing arrays (see #388), then you could write var (googleData, bingData, yahooData) = await Task.WhenAll(GetGoogleDataAsync(), GetBingDataAsync(), GetYahooDataAsync())
True, WhenAll isn't needed but I think it provides semantic value about the intent.
I wouldn't use .Result, it can lead to deadlocks in other situations and it won't unwrap exceptions. Also awaiting a completed Task doesn't harm.
Maybe an overload of Task.WhenAll, could return a ValueTuple, then you can easily deconstruct.
Can you not just use: https://www.nuget.org/packages/TaskTupleAwaiter/1.0.1
?
I wouldn't use .Result, it can lead to deadlocks in other situations and it won't unwrap exceptions.
In this case, if any of the tasks fault, then the await Task.WhenAll will throw, so you'll never get to the .Result. Calling .Result on a completed task will never deadlock. My point was that it's possible to just use googleTask.Result rather than bothering with googleData if you're concerned with reducing the number of lines.
Maybe an overload of Task.WhenAll, could return a ValueTuple, then you can easily deconstruct
The problem there is that there's already a params Task[] overload, so this will change how existing code compiles. Alhhough i suppose you could do Task.WhenAll((t1,t2))
That's fantastic didn't knew about it
Most helpful comment
Can you not just use: https://www.nuget.org/packages/TaskTupleAwaiter/1.0.1
?