Callback-Funktionen sind ein mächtiges Konzept in C#, das dir ermöglicht, flexiblen und wiederverwendbaren Code zu schreiben. In diesem umfassenden Guide zeige ich dir, wie Callbacks funktionieren, wann du sie einsetzen solltest und welche modernen Alternativen C# bietet.
- 1 C#: Was sind Callback-Funktionen?
- 2 Warum brauchst du Callbacks in C#?
- 3 Callback-Varianten in C#: Deine Werkzeugkiste
- 4 Async/Await: Die moderne Alternative in C#
- 5 Best Practices für Callbacks in C#
- 6 Callbacks vs. Alternativen: Wann was verwenden?
- 7 Performance-Tipps
- 8 Praxisbeispiel: HTTP-Request mit Callbacks
- 9 Fazit: Callbacks meistern in C#
C#: Was sind Callback-Funktionen?
Ein Callback ist eine Funktion, die als Parameter an eine andere Funktion übergeben wird und zu einem späteren Zeitpunkt ausgeführt wird. Stell dir vor, du gibst einem Kollegen eine Aufgabe und sagst: “Wenn du fertig bist, ruf mich bitte an.” Genau so funktionieren Callbacks in der Programmierung.
In C# implementierst du Callbacks typischerweise mit Delegates, Action, Func oder Events.
Warum brauchst du Callbacks in C#?
Callbacks lösen mehrere wichtige Probleme in der Software-Entwicklung:
- Asynchrone Operationen: Reagiere auf Ereignisse, wenn sie eintreten, ohne den Programmfluss zu blockieren
- Lose Kopplung: Trenne die Logik des Aufrufers von der des Empfängers
- Wiederverwendbarkeit: Schreibe generischen Code, der verschiedene Verhaltensweisen unterstützt
- Event-Driven Architecture: Implementiere Publish-Subscribe-Muster elegant
Callback-Varianten in C#: Deine Werkzeugkiste
1. Delegates: Die klassische Methode
Delegates sind typsichere Funktionszeiger in C#. Sie definieren eine Signatur, die eine Callback-Funktion erfüllen muss.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Delegate definieren public delegate void OperationCallback(string result); public class DataProcessor { public void ProcessData(string data, OperationCallback callback) { // Daten verarbeiten string result = data.ToUpper(); // Callback ausführen callback(result); } } // Verwendung var processor = new DataProcessor(); processor.ProcessData("hallo welt", (result) => { Console.WriteLine($"Ergebnis: {result}"); }); |
2. Action und Func: Die modernen Delegates
Action und Func sind vordefinierte generische Delegates, die dir viel Tipparbeit ersparen.
Action für Callbacks ohne Rückgabewert:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class FileUploader { public void UploadFile(string filePath, Action<int> progressCallback) { for (int i = 0; i <= 100; i += 10) { // Simuliere Upload-Fortschritt Thread.Sleep(100); progressCallback(i); } } } // Verwendung var uploader = new FileUploader(); uploader.UploadFile("document.pdf", (progress) => { Console.WriteLine($"Upload: {progress}%"); }); |
Func für Callbacks mit Rückgabewert:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Calculator { public int Calculate(int a, int b, Func<int, int, int> operation) { return operation(a, b); } } // Verwendung var calc = new Calculator(); int sum = calc.Calculate(5, 3, (x, y) => x + y); int product = calc.Calculate(5, 3, (x, y) => x * y); |
3. Events: Callbacks für Publisher-Subscriber-Muster
Events bauen auf Delegates auf und sind ideal für Benachrichtigungen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class DownloadManager { // Event definieren public event EventHandler<DownloadEventArgs> DownloadCompleted; public void StartDownload(string url) { // Download-Logik Thread.Sleep(2000); // Event auslösen OnDownloadCompleted(new DownloadEventArgs { Url = url, Success = true }); } protected virtual void OnDownloadCompleted(DownloadEventArgs e) { DownloadCompleted?.Invoke(this, e); } } public class DownloadEventArgs : EventArgs { public string Url { get; set; } public bool Success { get; set; } } // Verwendung var manager = new DownloadManager(); manager.DownloadCompleted += (sender, args) => { Console.WriteLine($"Download von {args.Url} abgeschlossen!"); }; manager.StartDownload("https://example.com/file.zip"); |
Async/Await: Die moderne Alternative in C#
Während klassische Callbacks ihren Platz haben, bietet C# mit async/await eine elegantere Lösung für asynchrone Operationen.
Vorher (mit Callbacks):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public void LoadData(Action<string> callback) { Task.Run(() => { Thread.Sleep(1000); callback("Daten geladen"); }); } // Callback-Hell vermeiden! LoadData((result1) => { Console.WriteLine(result1); LoadData((result2) => { Console.WriteLine(result2); }); }); |
Nachher (mit async/await):
1 2 3 4 5 6 7 8 9 10 11 12 |
public async Task<string> LoadDataAsync() { await Task.Delay(1000); return "Daten geladen"; } // Viel lesbarer! string result1 = await LoadDataAsync(); Console.WriteLine(result1); string result2 = await LoadDataAsync(); Console.WriteLine(result2); |
Best Practices für Callbacks in C#
1. Verwende Action und Func statt eigener Delegates
1 2 3 4 5 6 |
// Schlecht: Unnötiger Custom Delegate public delegate void MyCallback(string message); // Gut: Verwende Action public void DoSomething(Action<string> callback) { } |
2. Null-Checks nicht vergessen
1 2 3 4 5 6 |
public void ExecuteCallback(Action callback) { // Immer prüfen, ob der Callback null ist callback?.Invoke(); } |
3. Bevorzuge async/await für asynchrone Operationen
Callbacks führen schnell zu “Callback Hell” bei verschachtelten asynchronen Aufrufen. async/await macht deinen Code linear und lesbar.
4. Events für One-to-Many-Kommunikation
Wenn mehrere Subscriber auf ein Ereignis reagieren sollen, verwende Events statt einfacher Callbacks.
1 2 3 4 5 6 7 8 9 10 11 |
public class OrderProcessor { public event Action<Order> OrderPlaced; public void PlaceOrder(Order order) { // Mehrere Handler können subscriben OrderPlaced?.Invoke(order); } } |
Callbacks vs. Alternativen: Wann was verwenden?
Szenario | Empfehlung |
---|---|
Asynchrone I/O-Operationen | async/await mit Task |
Event-Benachrichtigungen | Events |
Strategie-Muster | Func/Action Parameter |
UI-Updates | Events oder IObservable |
Einfache Rückrufe | Action/Func |
Performance-Tipps
Callbacks haben minimalen Overhead, aber beachte diese Punkte:
- Closures: Lambda-Ausdrücke können Variablen capturen, was zu unerwarteter Lebensdauer führt
- Memory Leaks: Vergiss nicht, Event-Handler zu entfernen
- Thread-Safety: Callbacks können auf verschiedenen Threads ausgeführt werden
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Memory Leak vermeiden public class Subscriber { public void Subscribe(Publisher publisher) { publisher.DataChanged += OnDataChanged; } public void Unsubscribe(Publisher publisher) { // Wichtig: Handler entfernen! publisher.DataChanged -= OnDataChanged; } private void OnDataChanged(object sender, EventArgs e) { } } |
Praxisbeispiel: HTTP-Request mit Callbacks
Hier siehst du, wie du Callbacks in einem realistischen Szenario einsetzt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public class ApiClient { public void FetchUserData( int userId, Action<User> onSuccess, Action<Exception> onError) { try { // API-Aufruf simulieren Thread.Sleep(500); var user = new User { Id = userId, Name = "Max Mustermann" }; onSuccess(user); } catch (Exception ex) { onError(ex); } } } // Verwendung mit Error-Handling var client = new ApiClient(); client.FetchUserData( userId: 123, onSuccess: (user) => Console.WriteLine($"User: {user.Name}"), onError: (ex) => Console.WriteLine($"Fehler: {ex.Message}") ); |
Fazit: Callbacks meistern in C#
Callback-Funktionen sind ein fundamentales Konzept in C#, das dir hilft, flexiblen und erweiterbaren Code zu schreiben. Während klassische Delegates und Callbacks nach wie vor wichtig sind, bietet C# mit async/await, Events und Reactive Extensions moderne Alternativen für verschiedene Szenarien.
Merke dir:
- Action und Func für einfache Callbacks
- Events für Publisher-Subscriber-Muster
- async/await für asynchrone Operationen
- Immer Null-Checks und Memory Leaks im Blick behalten
Mit diesem Wissen bist du bestens gerüstet, um Callbacks in deinen C#-Projekten effektiv einzusetzen. Viel Erfolg beim Coden!
Vielleicht ebenfalls interessant für Dich:
Meistere Callback-Funktionen in Python