Ok, I found the answer myself after reading this https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/
Using the async keyword here, the compiler is about to display that delegate will be Func<Task<int>> : the delegate call will be returned to Task<int> to represent the possible completion of this call. And also since the delegate is Func<Task<int>> , TResult is equal to Task<int> , and therefore the type 't will be Task<Task<int>> , not Task<int> .
So, this code works as expected:
Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Factory.StartNew(async () => { await Task.Delay(4000); }); } for (var i = 0; i < tasks.Length; ++i) await await (tasks[i] as Task<Task>); Console.WriteLine("Done!");
What can be implemented with Unwrap :
Task[] tasks = new Task[4]; for (var i = 0; i < tasks.Length; ++i) { tasks[i] = Task.Factory.StartNew(async () => { await Task.Delay(4000); }).Unwrap(); } for (var i = 0; i < tasks.Length; ++i) await tasks[i]; Console.WriteLine("Done!");
source share