1. Einführung
In C# (und in .NET allgemein) sind Events eine der Möglichkeiten, wie Objekte miteinander kommunizieren. Zum Beispiel hast du einen Button, dessen Klick etwas auslösen soll. Man könnte das über die Deklaration einer separaten Methode realisieren und diese Methode dann explizit am Event anmelden... Aber oft möchte man einfach die Reaktion „direkt hier“ beschreiben, ohne die Logik über verschiedene Stellen der Datei zu verteilen.
Lambda-Ausdrücke lösen dieses Problem hervorragend — sie erlauben dir, die Reaktion auf ein Event genau an der Stelle zu schreiben, an der du dich darauf registrierst. Minimale Zeremonie — maximaler Nutzen.
Das Gleiche gilt für callbacks: manchmal übergibst du einer Methode etwas Logik, die sie später ausführen soll, z.B. wenn eine Operation fertig ist — und wieder machen Lambda-Ausdrücke das einfach und übersichtlich: die benötigte Logik steht direkt an der Aufrufstelle.
Events und callbacks: kurz auf den Punkt und wo Lambdas nützlich sind
Event ist im Grunde ein „Schild“ am Objekt: „hier kann sich jemand anmelden und etwas tun, wenn etwas passiert“.
Callback (Rückruf) ist „ich gebe dir jetzt eine Funktion, und du rufst sie auf, wenn es nötig ist“. Sehr ähnlich wie „Hinterlasse eine Nachricht — wir rufen zurück“.
Wenn du dich zuvor mit Delegates und Events beschäftigt hast, kennst du vielleicht so eine Syntax:
button.Click += MyButtonClickHandler;
Wobei MyButtonClickHandler eine spezielle Methode ist, die irgendwo deklariert werden muss. Wenn die Logik jedoch einfach ist, möchte man sich nicht mit einer extra Methode aufhalten.
Hier kommen Lambdas ins Spiel:
button.Click += (sender, args) => { Console.WriteLine("Taste gedrückt!"); };
Kompakt, klar, direkt hier!
2. Lambdas als Event-Handler: von einfach bis interessant
Einfache Form: die Lampe blinkt — wir schreiben in die Konsole
Angenommen, wir haben eine Klasse Button, und wir wollen auf ihr Event Click reagieren.
// Stellen wir uns so einen Button vor:
public class Button
{
public event EventHandler? Click;
public void SimulateClick() // Zum Beispiel: wir "drücken" programmatisch
{
// Wenn sich jemand angemeldet hat — rufen wir die Handler auf
Click?.Invoke(this, EventArgs.Empty);
}
}
Jetzt verwenden wir diesen Button:
var button = new Button();
// Wir abonnieren das Event des Buttons mit einer Lambda!
button.Click += (sender, args) =>
{
Console.WriteLine("Hurra! Der Button wurde gedrückt!");
};
button.SimulateClick(); // => Hurra! Der Button wurde gedrückt!
Erläuterung:
— Alles nach => ist der Körper deiner „Mini-Funktion“, die ausgeführt wird, wenn das Event eintritt.
— Du musst dich nicht um den Lebenszyklus des Handlers kümmern: er lebt so lange wie deine Anmeldung (+=). Wichtig: wenn die Lambda externe Variablen captured und du dich nicht vom Event abmeldest, kann das zu Memory Leaks führen.
Lambda-Handler mit Variable-Capturing
int clickCount = 0;
button.Click += (sender, args) =>
{
clickCount++;
Console.WriteLine($"Der Button wurde bereits {clickCount} mal gedrückt!");
};
button.SimulateClick(); // => Der Button wurde bereits 1 mal gedrückt!
button.SimulateClick(); // => Der Button wurde bereits 2 mal gedrückt!
Was passiert:
Die Lambda "captured" die Variable clickCount von außen und merkt sich ihren Wert zwischen Aufrufen.
3. Einsatz von Lambda-Ausdrücken für callbacks
Callback wird oft dann verwendet, wenn Code deine Funktion später aufrufen soll — z.B. nach Abschluss einer längeren Arbeit.
Eine Lambda als callback übergeben
Angenommen, wir haben eine Methode, die einen Delegate oder eine Lambda als Argument annimmt:
void DoWork(Action callback)
{
Console.WriteLine("Die Arbeit beginnt...");
// Arbeit simulieren
System.Threading.Thread.Sleep(500); // (Das sollte man in realen Anwendungen nicht tun, das blockiert!)
callback(); // Nach der Arbeit rufen wir den callback auf
}
DoWork(() => Console.WriteLine("Arbeit abgeschlossen!"));
Ergebnis:
Zuerst erscheint in der Konsole "Die Arbeit beginnt...", dann "Arbeit abgeschlossen!".
Du kannst Lambdas mit Parametern übergeben:
void Calculate(int a, int b, Action<int> onResult)
{
int sum = a + b;
onResult(sum);
}
Calculate(5, 8, result => Console.WriteLine($"Ergebnis: {result}"));
4. Typische Fehler bei der Verwendung von Lambdas
Nichtrückgängiges Abmelden von Events
Wenn du dich mit einer Lambda auf ein Event anmeldest, hast du keinen „Namen des Handlers“, um dich später einfach abzumelden:
button.Click += (s, e) => Console.WriteLine("...");
button.Click -= ??? // Wie hier deine Lambda übergeben? Gar nicht, wenn du sie nicht gespeichert hast.
Wenn du dich wirklich abmelden musst — speichere die Lambda in einer Variable:
EventHandler handler = (s, e) => Console.WriteLine("...");
button.Click += handler;
// ...dann
button.Click -= handler;
Das ist wichtig für langlebige Objekte: wenn du dich nicht abmeldest, bleibt die Referenz bestehen und kann zu Memory Leaks führen.
Capturing von Schleifenvariablen
Klassiker: Anmelden auf Events innerhalb einer Schleife:
for (int i = 0; i < 3; i++)
button.Click += (s, e) => Console.WriteLine(i); // Alle Lambdas "merken" sich dasselbe i
In modernen C#-Versionen wurde dieses Verhalten für foreach korrigiert, aber bei for kann es manchmal noch zu Überraschungen kommen — sei also vorsichtig mit gecaptureten Variablen!
Wenn jede Lambda ihren eigenen Wert behalten soll — erstelle eine lokale Kopie:
for (int i = 0; i < 3; i++)
{
int localI = i;
button.Click += (s, e) => Console.WriteLine(localI);
}
GO TO FULL VERSION