Auf der PDC 2010 in Redmond gab Anders Hejlsberg einen weiteren Ausblick auf die Zukunft von C#. Während bei Version 4 der Entwicklungssprache “dynamic” im Vordergrund stand, ist C# 5 vor allem für asynchrones programmieren (neben anderen Verbesserungen) ein zentrales Thema. Die Abarbeitung von Aufgaben, welche über ein Netzwerk gehen oder aus anderen Gründen länger brauchen waren stets komplexe Vorgänge. Es gab hierfür meist 2 Wege:
1. Alles synchron abarbeiten
Dies führte dazu, das der Thread blockierte bis die Abarbeitung fertig war. Vor allem bei großen Datenübertragungen aus dem Netz, großen Dateien oder ähnlichem führte dies oft zu Problemen. Daher mussten solche Vorgänge, wollte man die UI soweit haben das diese reagiert, parallelisieren. Dies führte zu Punkt 2:
2. Asynchrone Methoden
Hierbei wird ein Callback aufgerufen, wenn ein Download oder ähnliches Fertig ist. Dies hatte jedoch den Nachteil, das es den Code unnötig verkomplizierte und Callback-Zuweisungen notwendig machte. Außerdem erschwerte es die Fehlerbehandlung, da etwas, das oft zusammen gehört auf zwei Methoden aufgeteilt wurde.
Asynchrones entwickeln hatte zwar viele Vorteile, jedoch den Nachteil das es im Code “nicht so schön” wie eine synchrone Methode aussieht. Mit der nächsten Version von C# wird dies nun wesentlich vereinfacht. Kurzum: es ist so schön leserlich wie eine synchrone Entwicklung, jedoch asynchron und blockiert dadurch keinen Thread. Alles was man benötigt sind diese zwei Keywords:
async
await
“async” markiert eine Methode für einen asyncronen Aufruf, “await” stellt diesen dar. Ferner wird noch der “Task” verwendet, welcher als Rückgabe einer Methode mit asynchronen Aufruf dient. Die folgende Methode ist synchron und lässt in einem ViewModel die WPF Anwendung für 5 sekunden einfrieren:
public void Query(string symbol)
{
Effect = new BlurEffect() { Radius = 20.0 };
WebClient wc = new WebClient();
string result = wc.DownloadString(string.Format(target, symbol));
var splitted = result.Trim().Split('\n').Skip(1);
Symbols.Clear();
foreach (var item in splitted)
{
Symbols.Add(SymbolViewModel.Create(item.Split(',')));
}
Effect = null;
}
Da diese Methode nicht asynchron abläuft. Dies hat zum Effekt das der Benutzer viel herumklickt und es “geschieht” nichts. Baut man diese Lösung auf die neuen Möglichkeiten mit C# um, so sieht dies folgendermaßen aus:
public async Task QueryAsync(string symbol)
{
Effect = new BlurEffect() { Radius = 20.0 };
WebClient wc = new WebClient();
string result = await wc.DownloadStringTaskAsync(string.Format(target, symbol));
var splitted = result.Trim().Split('\n').Skip(1);
Symbols.Clear();
foreach (var item in splitted)
{
Symbols.Add(SymbolViewModel.Create(item.Split(',')));
}
Effect = null;
}
Hier läuft alles asynchron ab und das UI wird nicht blockiet. es waren nur wenige Abänderungen notwendig: 1.) Methode mit “async” versehen, 2.) einen Task zurückgeben, 3.) await vor DownloadString einfügen und 4.) statt “DownloadString” die Methode “DownloadStringTaskAsync” verwenden. Der Compiler kümmert sich um alles was hier asynchron ist – inklusive des Callbacks. Als Entwickler bekommt man vom asynchronen Aufruf nichts mehr mit. Durch das Keyword “await” wird im Hintergrund ein Delegate mit der restlichen Methode erstellt.