Your problem is due to LINQ's deferred execution. In particular, Task.WhenAll
is appropriately waiting for the tasks to complete. However, when you call ElementAt
, the sequence is re-evaluated, creating a new Foo
and Task
.
So, this would also not work:
var ordinals = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
var foos = ordinals.Select( o => new Foo() ); //.ToList();
// Get the first Foo, creating it.
var first = foos.ElementAt(0);
// This gets a *different* Foo. It creates it again.
var other = foos.ElementAt(0);
MessageBox.Show((first == other).ToString()); // Displays "false"
In general, it's a good idea to "reify" your sequence (using ToArray
or similar) when dealing with any operations with side effects, including starting async
operations. Task.WhenAll
will reify your sequence internally, but then if you evaluate it again (e.g., ElementAt
), you get unexpected behavior.