Stai ricevendo quell'errore perché la Task
classe ha già avviato l'attività prima di dartela. Dovresti sempre e solo richiamare Start
un'attività che crei chiamando il suo costruttore, e non dovresti nemmeno farlo a meno che tu non abbia una ragione valida per non avviare l'attività quando la crei; se vuoi che inizi subito dovresti usare Task.Run
o Task.Factory.StartNew
sia per creare che per iniziarne uno nuovo Task
.
Quindi, ora sappiamo che dobbiamo sbarazzarci di quel fastidioso Start
. Eseguirai il tuo codice e scoprirai che la finestra del messaggio viene visualizzata subito, non 5 secondi dopo, che succede?
Bene, Task.Delay
ti dà solo un'attività che sarà completata in 5 secondi. Non interrompe l'esecuzione del thread per 5 secondi. Quello che vuoi fare è avere del codice che viene eseguito al termine di quell'attività. Ecco a cosa ContinueWith
serve. Ti consente di eseguire del codice al termine di una determinata attività:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
Ciò si comporterà come previsto.
Potremmo anche sfruttare la await
parola chiave di C # 5.0 per aggiungere continuazioni più facilmente:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
Mentre una spiegazione completa di quello che sta succedendo qui va oltre lo scopo di questa domanda, il risultato finale è un metodo che si comporta in modo molto simile al metodo precedente; mostrerà una finestra di messaggio 5 secondi dopo aver chiamato il metodo, ma il metodo stesso tornerà [quasi] subito in entrambi i casi. Detto questo, await
è molto potente e ci permette di scrivere metodi che sembrano semplici e diretti, ma che sarebbero molto più difficili e complicati da scrivere usando ContinueWith
direttamente. Inoltre semplifica notevolmente la gestione degli errori, eliminando molto codice standard.
Wait()
a un'attività bloccherà il thread corrente finché l'attività non verrà risolta. Non è quasi mai quello che vuoi che accada.