Asynchrone Programmierung in C#: Vollständiger Leitfaden für Anfänger
\n\nAsynchrone Programmierung ist eines der Schlüsselkonzepte der modernen C#-Entwicklung. Sie ermöglicht es Ihren Anwendungen, reaktionsfähig zu bleiben, ohne den Ausführungsthread während langer Operationen zu blockieren: Dateilesen, Datenbankabfragen oder HTTP-Aufrufe. In diesem Leitfaden erläutern wir die Grundlagen der Asynchronität in C# anhand praktischer Beispiele.
\n\nWas ist asynchrone Programmierung und warum wird sie benötigt?
\n\nIn der synchronen Programmierung wird Code sequenziell ausgeführt. Wenn Sie eine Methode aufrufen, die 5 Sekunden auf eine Antwort vom Server wartet, friert der gesamte Thread (UI oder Arbeits-Thread) ein. Die Anwendung "hängt". Asynchrone Programmierung löst dieses Problem: Anstatt den Thread zu blockieren, gibt die Methode die Kontrolle an den aufrufenden Code zurück und benachrichtigt, wenn das Ergebnis bereit ist.
\n\nDie Hauptvorteile der Asynchronität:
\n- \n
- UI-Reaktionsfähigkeit — Die Oberfläche friert bei langen Operationen nicht ein. \n
- Skalierbarkeit — Serveranwendungen können mehr Anfragen verarbeiten, ohne neue Threads zu erstellen. \n
- Effizienz — Freigegebene Threads werden für andere Aufgaben genutzt. \n
Grundlagen von async/await in C#
\n\nDie Schlüsselwörter async und await sind die Grundlage der asynchronen Programmierung in C#. Sie wurden in C# 5.0 eingeführt und machen asynchronen Code fast so einfach wie synchronen.
Verwendungsregeln:
\n- \n
- Die Methode wird mit dem Schlüsselwort
asyncmarkiert. \n - Der Rückgabetyp muss
Task,Task<T>odervoid(nur für Ereignisbehandler) sein. \n - Rufen Sie innerhalb der Methode andere asynchrone Methoden mit dem Schlüsselwort
awaitauf. \n
Einfaches Beispiel:
\nusing System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n Console.WriteLine("Starte Download...");\n string content = await DownloadWebPageAsync("https://example.com");\n Console.WriteLine($"Geladene Zeichen: {content.Length}");\n }\n\n static async Task<string> DownloadWebPageAsync(string url)\n {\n using HttpClient client = new HttpClient();\n string result = await client.GetStringAsync(url);\n return result;\n }\n}\n\nBeachten Sie: Die Methode Main ist ebenfalls als async Task markiert – dies ist seit C# 7.1 zulässig.
Typen Task, Task<T> und ValueTask
\n\nIn der asynchronen Programmierung in C# werden drei Haupttypen von Rückgabewerten verwendet:
\n\n- \n
Task— für Methoden, die keinen Wert zurückgeben (Analogon zu void). \n Task<T>— für Methoden, die einen Wert vom Typ T zurückgeben. \n ValueTask<T>— optimierte Version für Szenarien, in denen das Ergebnis oft synchron verfügbar ist (z. B. aus dem Cache). \n
Beispiel mit Task<T>:
\nstatic async Task<int> CalculateSumAsync(int a, int b)\n{\n await Task.Delay(1000); // Simulation langer Arbeit\n return a + b;\n}\n\n// Aufruf:\nint result = await CalculateSumAsync(5, 3);\nConsole.WriteLine(result); // 8\n\nFehlerbehandlung in asynchronen Methoden
\n\nAusnahmen in asynchronen Methoden werden mit dem Standardblock try-catch behandelt. Es gibt jedoch eine wichtige Nuance: Die Ausnahme wird im Task-Objekt gespeichert und bei Verwendung von await erneut "ausgelöst".
static async Task<string> ReadFileAsync(string path)\n{\n try\n {\n string content = await File.ReadAllTextAsync(path);\n return content;\n }\n catch (FileNotFoundException ex)\n {\n Console.WriteLine($"Datei nicht gefunden: {ex.Message