Ich glaube, Sie werden hier ein paar Dinge durcheinander bringen. Was Sie für Fragen ist bereits möglich , mit System.Threading.Tasks
dem async
und await
in C # 5 werden nur für die gleiche Funktion einen wenig schöner syntaktischen Zucker zu liefern.
Lassen Sie uns ein Winforms-Beispiel verwenden - fügen Sie eine Schaltfläche und ein Textfeld in das Formular ein und verwenden Sie diesen Code:
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;
}
Führen Sie es aus und Sie werden sehen, dass (a) es den UI-Thread nicht blockiert und (b) Sie nicht die übliche Fehlermeldung "Cross-Thread-Operation ungültig" erhalten - es sei denn, Sie entfernen das TaskScheduler
Argument aus dem letzten ContinueWith
, in Welchen Fall wirst du.
Dies ist ein moorhafter Fortführungsstil . Die Magie geschieht in der TaskScheduler
Klasse und speziell in der Instanz, die von abgerufen wird FromCurrentSynchronizationContext
. Übergeben Sie dies an eine beliebige Fortsetzung, und geben Sie an, dass die Fortsetzung auf dem Thread ausgeführt werden muss, der die FromCurrentSynchronizationContext
Methode aufgerufen hat - in diesem Fall auf dem UI-Thread.
Kellner sind etwas anspruchsvoller in dem Sinne, dass sie wissen, auf welchem Thread sie begonnen haben und auf welchem Thread die Fortsetzung stattfinden muss. So kann der obige Code etwas natürlicher geschrieben werden:
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;
}
Diese beiden sollten sehr ähnlich aussehen, und tatsächlich sind sie sich sehr ähnlich. Die DelayedAddAsync
Methode gibt jetzt ein Task<int>
statt eines zurück int
, und daher werden await
nur die Fortsetzungen auf jede dieser Methoden angewendet. Der Hauptunterschied besteht darin, dass der Synchronisierungskontext in jeder Zeile weitergegeben wird, sodass Sie dies nicht explizit wie im letzten Beispiel ausführen müssen.
Theoretisch sind die Unterschiede viel bedeutender. Im zweiten Beispiel button1_Click
wird tatsächlich jede einzelne Zeile in der Methode im UI-Thread ausgeführt, aber die Task selbst ( DelayedAddAsync
) wird im Hintergrund ausgeführt. Im ersten Beispiel läuft alles im Hintergrund , mit Ausnahme der Zuweisung, textBox1.Text
die wir explizit dem Synchronisationskontext des UI-Threads zugeordnet haben.
Das ist es, was wirklich interessant ist await
- die Tatsache, dass ein Kellner in der Lage ist, auf dieselbe Weise ein- und auszuspringen , ohne Anrufe zu blockieren. Sie rufen await
, den aktuellen Thread Nachrichten an die Verarbeitung geht zurück, und wenn es fertig ist, wird die Erwartenden genau abholen, wo sie aufgehört hat , im selben Thread aufhörte es in. Aber in Bezug auf Ihre Invoke
/ BeginInvoke
Kontrast in der Frage, I‘ Es tut mir leid zu sagen, dass Sie das schon vor langer Zeit aufgeben sollten.
await
Bezug auf die Funktionalität höchst unwahrscheinlich . Es ist nur eine Menge syntaktischer Zucker für die Weitergabe . Möglicherweise gibt es noch einige andere Verbesserungen an WinForms, die helfen sollen? Dies würde jedoch unter das .NET-Framework fallen und nicht unter C #.