Penso che stai confondendo alcune cose, qui. Quello che stai chiedendo è già possibile utilizzare System.Threading.Tasks, asynce awaitin C # 5 forniranno solo un po 'di zucchero sintattico più carino per la stessa funzione.
Facciamo un esempio di Winforms: rilascia un pulsante e una casella di testo sul modulo e usa questo codice:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int DelayedAdd(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
Eseguilo e vedrai che (a) non blocca il thread dell'interfaccia utente e (b) non ottieni il solito errore "operazione cross-thread non valida" - a meno che tu non rimuova l' TaskSchedulerargomento dall'ultimo ContinueWith, in quale caso lo farai.
Questo è lo stile di passaggio di continuazione standard . La magia avviene in TaskSchedulerclasse e in particolare l'istanza recuperata da FromCurrentSynchronizationContext. Passalo in qualsiasi continuazione e dici che la continuazione deve essere eseguita su qualsiasi thread chiamato FromCurrentSynchronizationContextmetodo - in questo caso, il thread dell'interfaccia utente.
Gli spettatori sono leggermente più sofisticati, nel senso che sono consapevoli di quale thread hanno iniziato e su quale thread deve avvenire la continuazione. Quindi il codice sopra può essere scritto un po ' più naturalmente:
private async void button1_Click(object sender, EventArgs e)
{
int a = await DelayedAddAsync(5, 10);
int b = await DelayedAddAsync(a, 20);
int c = await DelayedAddAsync(b, 30);
int d = await DelayedAddAsync(c, 50);
textBox1.Text = d.ToString();
}
private async Task<int> DelayedAddAsync(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
Questi due dovrebbero apparire molto simili e in effetti sono molto simili. Il DelayedAddAsyncmetodo ora restituisce un Task<int>invece di un int, e quindi awaitsta semplicemente schiaffeggiando continuazioni su ognuna di quelle. La differenza principale è che passa lungo il contesto di sincronizzazione su ogni riga, quindi non è necessario farlo esplicitamente come abbiamo fatto nell'ultimo esempio.
In teoria le differenze sono molto più significative. Nel secondo esempio, ogni singola riga del button1_Clickmetodo viene effettivamente eseguita nel thread dell'interfaccia utente, ma l'attività stessa ( DelayedAddAsync) viene eseguita in background. Nel primo esempio, tutto viene eseguito in background , tranne l'assegnazione a textBox1.Textcui abbiamo esplicitamente associato il contesto di sincronizzazione del thread dell'interfaccia utente.
Questo è ciò che è davvero interessante await: il fatto che un cameriere è in grado di entrare e uscire dallo stesso metodo senza bloccare le chiamate. Chiama await, il thread corrente ritorna all'elaborazione dei messaggi e, quando è finito, il cameriere riprenderà esattamente da dove era stato interrotto, nello stesso thread in cui era stato interrotto. Ma in termini di Invoke/ BeginInvokecontrasto nella domanda, io ' Mi dispiace dire che avresti dovuto smettere di farlo molto tempo fa.
awaitfunzionalità. È solo un sacco di zucchero sintattico per il passaggio di seguito . Forse ci sono altri miglioramenti non correlati a WinForms che dovrebbero aiutare? Ciò rientrerebbe tuttavia nel framework .NET stesso e non nello specifico C #.