O problema é que você está usando a Taskclasse não genérica , que não pretende produzir um resultado. Portanto, quando você cria a Taskinstância passando um delegado assíncrono:
Task myTask = new Task(async () =>
... o delegado é tratado como async void. Um async voidnão é um Task, não pode ser esperado, sua exceção não pode ser tratada e é uma fonte de milhares de perguntas feitas por programadores frustrados aqui no StackOverflow e em outros lugares. A solução é usar a Task<TResult>classe genérica , porque você deseja retornar um resultado, e o resultado é outro Task. Então você tem que criar um Task<Task>:
Task<Task> myTask = new Task<Task>(async () =>
Agora, quando você for Startexterno Task<Task>, será concluído quase instantaneamente, porque seu trabalho é apenas criar o interior Task. Você terá que aguardar o interior Tasktambém. É assim que isso pode ser feito:
myTask.Start();
Task myInnerTask = await myTask;
await myInnerTask;
Você tem duas alternativas. Se você não precisar de uma referência explícita ao interno Task, poderá aguardar o externo Task<Task>duas vezes:
await await myTask;
... ou você pode usar o método de extensão Unwrapinterno que combina as tarefas externa e interna em uma:
await myTask.Unwrap();
Esse desempacotamento acontece automaticamente quando você usa o Task.Runmétodo muito mais popular que cria tarefas quentes, portanto, ele Unwrapnão é usado com muita frequência atualmente.
Caso você decida que seu representante assíncrono deve retornar um resultado, por exemplo string, a , declare que a myTaskvariável é do tipo Task<Task<string>>.
Nota: Eu não apoio o uso de Taskconstrutores para criar tarefas frias. Como uma prática geralmente é desaprovada, por motivos que eu realmente não conheço, mas provavelmente porque é usada tão raramente que tem o potencial de capturar outros usuários / mantenedores / revisores desconhecidos do código de surpresa.
Conselho geral: tenha cuidado sempre que estiver fornecendo um delegado assíncrono como argumento para um método. Idealmente, esse método deve esperar um Func<Task>argumento (o que significa que compreende delegados assíncronos) ou pelo menos um Func<T>argumento (o que significa que pelo menos o gerado Tasknão será ignorado). No infeliz caso em que esse método aceite um Action, seu delegado será tratado como async void. Isso raramente é o que você deseja, se é que alguma vez.