9

I have the following code in C#, VS2012, WPF 4.5. My expectation would be that, .ContinueWith will be executed after the task has finished completely (that's a continuation's whole purpose, isn't it?).

This should result in a value of 2 in finalResult.

int myTestInt = 0;

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

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

In fact, finalResult is assigned a value of 1 instead. So it seems like the continuation is started on the await statement already.

Is this the intended behaviour? Am I missing something here? Can't I rely on ContinueWithto start after a task has completely finished?

Update:

Justin's answer just inspired me to check the following:

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 is still set to 1. Is there no way to reliably wait for a task that contains awaits to complete?

Jason C
  • 38,729
  • 14
  • 126
  • 182
Frank im Wald
  • 896
  • 1
  • 11
  • 28

3 Answers3

10

When you pass an async delegate to Task.Factory.StartNew, the returned Task only represents the first portion of that delegate (up until the time it awaits something that is not already completed).

However, if you pass an async delegate to the new Task.Run method (which was included for this reason), the returned Task represents the entire delegate. So you can use ContinueWith as you expect. (Although await is usually a better option than ContinueWith).

For more information on StartNew vs Run, see Stephen Toub's post on the topic.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
4

The await will immediately return control to the calling function, which in this case is the StartNew of your task. This means the task will then complete and execute the ContinueWith. If you really want task to complete before the ContinueWith, then don't await the Task.Delay.

Justin Harvey
  • 14,446
  • 2
  • 27
  • 30
  • I think you're right - await marks the current task as completed. Although it's not (at least not from a semantical point of view). As await's are a basic building block of all software today, that means never to rely on ContinueWith anymore. Don't you think, that's a bug? – Frank im Wald Nov 08 '12 at 10:10
-1

I saw this in the 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);
    });
}

So do not forget the "async()" !!!

Jens
  • 1
  • His code has the `async` his problem is he is using `TaskFactory` which does not have a overload that takes in a `Func` or a `Func>` which `Task.Run` does have. – Scott Chamberlain Oct 30 '15 at 16:32