Продолжение начинается до завершения задачи.

У меня есть следующий код в C#, VS2012, WPF 4.5. Я ожидаю, что .ContinueWith будет выполнен после того, как задача будет полностью завершена (это и есть цель продолжения, не так ли?).

Это должно привести к значению 2 в finalResult,

int myTestInt = 0;

Task task = Task.Factory.StartNew(async () =>
{
   myTestInt = 1;
   await Task.Delay(TimeSpan.FromSeconds(6));
   myTestInt = 2;

}).ContinueWith(_ =>
   {
      int finalResult = myTestInt;
   });

По факту, finalResult вместо этого присваивается значение 1. Так что похоже, что продолжение начато на await заявление уже.

Это предполагаемое поведение? Я что-то здесь упускаю? Я не могу положиться на ContinueWithначать после того, как задача полностью завершена?

Обновить:

Ответ Джастина просто вдохновил меня проверить следующее:

int myTestInt = 0;
Task task=Task.Factory.StartNew(async () =>
{
   myTestInt = 1;
   await Task.Delay(TimeSpan.FromSeconds(6));
   myTestInt = 2;
});

task.Wait();
int result2 = myTestInt;

finalResult по-прежнему установлен в 1. Нет ли способа надежно ждать задачи, которая содержит awaitс завершить?

3 ответа

Решение

Когда вы передаете async делегировать Task.Factory.StartNew, вернулся Task представляет только первую часть этого делегата (до awaitчто-то, что еще не завершено).

Однако, если вы передадите async делегировать в новый Task.Run метод (который был включен по этой причине), возвращаемый Task представляет весь делегат. Так что вы можете использовать ContinueWith как вы ожидаете. (Хотя await обычно лучший вариант, чем ContinueWith).

Для получения дополнительной информации о StartNew против Runсм . пост Стивена Туба по теме.

Ожидание немедленно вернет управление вызывающей функции, которая в этом случае является StartNew вашей задачи. Это означает, что задача будет затем завершена и выполнит ContinueWith. Если вы действительно хотите, чтобы задача была выполнена до ContinueWith, не ждите Task.Delay.

Я видел это в MSDN::-)

public async  void button1_Click(object sender, EventArgs e)
{
    pictureBox1.Image = await Task.Run(async() =>
    {
        using(Bitmap bmp1 = await DownloadFirstImageAsync())
        using(Bitmap bmp2 = await DownloadSecondImageAsync())
        return Mashup(bmp1, bmp2);
    });
}

Так что не забывайте "async ()"!!!

Другие вопросы по тегам