2012-11-08 4 views
9

Ho il seguente codice in C#, VS2012, WPF 4.5. La mia aspettativa sarebbe che, .ContinueWith verrà eseguito dopo che l'attività è stata completata completamente (che è l'intero scopo della continuazione, non è vero?).. Si avvia prima che l'attività sia completata

Ciò dovrebbe comportare un valore di 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; 
    }); 

Infatti, finalResult viene assegnato un valore di 1, invece. Quindi sembra che la continuazione sia già iniziata sulla dichiarazione await.

È questo il comportamento previsto? Mi sto perdendo qualcosa qui? Non posso contare su ContinueWith per iniziare dopo che un'attività è stata completata?

Aggiornamento:

risposta di Justin appena mi ha ispirato a verificare quanto segue:

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 è ancora impostato a 1. Non c'è modo di aspettare in modo affidabile per un'attività che contiene await s per completare ?

+4

Penso che dovresti invocare 'Task.Delay' direttamente - non usando la parola chiave' await'. –

+2

Si noterà che '_' è in realtà un' Task ', che supporta completamente ciò che sta dicendo Justin ... –

+0

Infatti, l'uso di Task.Delay (6) produrrà il risultato previsto, ma non attenderà 6 secondi . Penso che sarebbe praticamente lo stesso per cancellare l'intera linea. –

risposta

10

Quando si passa un async delegato Task.Factory.StartNew, restituita Task rappresenta solo la prima parte di quella delegato (fino al momento await s qualcosa che che non è già completato).

Tuttavia, se si passa un delegato (incluso per questo motivo) al nuovo metodo Task.Run, il reso Task rappresenta l'intero delegato. Quindi puoi usare ContinueWith come ti aspetti. (Sebbene await sia in genere un'opzione migliore rispetto a ContinueWith).

Per ulteriori informazioni su StartNew rispetto a Run, vedere Stephen Toub's post on the topic.

+0

Il post collegato lo rende molto chiaro. Grazie!! –

4

L'attesa restituirà immediatamente il controllo alla funzione di chiamata, che in questo caso è il StartNew del compito. Ciò significa che l'attività quindi completerà ed eseguirà ContinueWith. Se si desidera veramente completare l'attività prima di ContinueWith, non attendere Task.Delay.

+0

Penso che tu abbia ragione: attendere contrassegna l'attività corrente come completata. Anche se non lo è (almeno non da un punto di vista semantico). Poiché le attese sono un elemento fondamentale di tutti i software oggi, ciò significa non affidarsi mai a ContinueWith. Non pensi, questo è un bug? –

-1

ho visto questo in 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); 
    }); 
} 

Quindi non dimenticare la "async()" !!!

+0

Il suo codice ha il 'async' il suo problema è che sta usando' TaskFactory' che non ha un sovraccarico che contiene un 'Func ' o un 'Func >' che 'Task.Run' ha. –