Ожидание async/ожидание внутри задачи

У меня есть эта конструкция в моей main(), которая создает

var tasks = new List<Task>();

var t = Task.Factory.StartNew(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

//DoBar not completed
t.Wait();
//Foo.Fim() done, Foo.DoBar should be but isn't

Однако, когда я .Wait для t, он не будет ждать завершения вызова DoBar(). Как я могу заставить его ждать?

Ответ 1

Не рекомендуется использовать Task.Factory.StartNew с async-await, вместо этого следует использовать Task.Run:

var t = Task.Run(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

Task.Factory.StartNew api был создан до асинхронного шаблона (TAP) на основе задач и async-await. Он вернет Task<Task>, потому что вы запускаете задачу с выражением лямбда, которое является асинхронным, и поэтому возвращает задачу. Unwrap будет извлекать внутреннюю задачу, но Task.Run будет неявно делать это для вас.


Для более глубокого сравнения всегда есть соответствующая статья Стивена Туба: Task.Run vs Task.Factory.StartNew

Ответ 2

Кажется, что я получаю желаемую функциональность Unwrap() задачи. Я не совсем уверен, что я объясню это, но я полагаю, что это работает.

var t = Task.Factory.StartNew(
            async () =>
                {
                        Foo.Fim();
                        await Foo.DoBar();
                }).Unwrap();

edit: Я искал ddescription Unwrap(): Creates a proxy Task that represents the asynchronous operation of a Task<Task<T>> Я думал, что это традиционно, что делала эта задача, но если мне нужно вызвать разворот, я полагаю, что это хорошо.

Ответ 3

Недавно я столкнулся с подобной проблемой и выяснил, что все, что вам нужно сделать, это DoBar() вернуть некоторое значение и использовать .Result вместо wait.

var g = Task.Run(() => func(arg));

var val = g.Result;

Это будет ждать, пока func вернет свой вывод и назначит его val.