1. Einführung
Vielleicht wusstest du das nicht, aber eine der beliebtesten Fragen im Vorstellungsgespräch ist: „Was weißt du über Lambda-Ausdrücke?“. Warum wird danach gefragt? Weil das eine sehr praktische und „modische“ Sache in C# ist, die es erlaubt, weniger Code zu schreiben und ihn ausdrucksstärker zu machen. Wenn anonyme Methoden wie handschriftliche Briefe sind, dann sind Lambda-Ausdrücke wie eine Nachricht im Messenger: schnell, kompakt und manchmal sogar mit Emojis (na ja, fast).
Lambda-Ausdrücke kamen mit C# Version 3.0 und haben sich seitdem überall verbreitet: in LINQ, Event-Handlern, Threads, Collections und sogar in KI-Bibliotheken auf .NET.
Ein Lambda-Ausdruck ist eine Möglichkeit, eine Methode direkt im Code „am Ort“ zu deklarieren, ohne Namen, superkurz und klar. Der Grundsyntax sieht immer so aus:
(parameter) => ausdruck_oder_codeblock
Dieser „Chevron“ => wird „Lambda-Operator“ oder „Pfeil“ genannt.
Eine kleine Analogie
Erinnere dich, wie du ein Rezept schreibst: „Einen Apfel nehmen, ihn schneiden, in die Schüssel legen“.
In C# wäre das:
(jabloko) => porizat(jabloko)
2. Einen anonymen Method in ein Lambda umwandeln
Angenommen, wir haben einen Delegate:
delegate int SquareDelegate(int x);
Die anonyme Methode sähe so aus:
SquareDelegate sq = delegate(int x) {
return x * x;
};
Und jetzt dasselbe als Lambda-Ausdruck:
SquareDelegate sq = (int x) => { return x * x; };
Aber C# kann die Typen erraten, und wir können es weiter verkürzen:
SquareDelegate sq = x => x * x;
Erstaunliche Kompaktheit!
Vergleich mit einer „normalen“ Methode und einer anonymen Funktion
| Art | Deklaration | Wo verwendbar | Nachteile |
|---|---|---|---|
| Benannte Methode | In der Klasse | Überall | Braucht einen Namen, mehr Code |
| Anonyme Methode | Im Code | Nur mit Delegates | Etwas umständlicher Syntax |
| Lambda-Ausdruck | Im Code | Überall mit Delegates | Manchmal ist der Typ nicht sofort offensichtlich |
3. Syntax von Lambda-Ausdrücken: Varianten
Parameter
Ohne Parameter:
Action hello = () => Console.WriteLine("Hallo, Welt!");
Ein Parameter (Klammern können weggelassen werden):
Func<int, int> inc = x => x + 1;
Mehrere Parameter (Klammern nötig):
Func<int, int, int> sum = (a, b) => a + b;
Rumpf des Lambdas
Ein Ausdruck — ohne geschweifte Klammern und ohne return:
x => x * x
Codeblock — geschweifte Klammern, return benötigt:
(x, y) =>
{
int z = x + y;
return z * z;
}
Parameter-Typen
Meistens musst du den Typ nicht angeben — der Compiler schlussfolgert ihn. Aber wenn du magst, gerne:
(x, y) => x + y // Der Compiler leitet die Typen ab.
(int x, int y) => x + y // Man kann explizit angeben.
4. Feinheiten und realistischere Beispiele
Verwendung mit Collections
Erinnere dich an unsere kleine Lehr-Anwendung (zum Beispiel eine Liste von Nutzern)? Angenommen, wir haben ein Array von Zahlen:
int[] numbers = { 1, 2, 3, 4, 5 };
Wir wollen nur gerade Zahlen auswählen:
var evenNumbers = numbers.Where(n => n % 2 == 0);
Hier ist Where eine LINQ-Extension-Methode und die Bedingung ist unser Lambda-Filter.
Übergabe an eine Methode
Angenommen, wir haben einen Delegate-Method:
public delegate bool Filter(int number);
public static int[] FilterNumbers(int[] data, Filter predicate)
{
var result = new List<int>();
foreach (var n in data)
if (predicate(n))
result.Add(n);
return result.ToArray();
}
Jetzt übergeben wir einen Lambda-Ausdruck:
int[] evens = FilterNumbers(numbers, n => n % 2 == 0);
Lambda als Event-Handler
button.Click += (sender, args) => Console.WriteLine("Button geklickt!");
5. Lambdas und die Standard-Generic-Delegates
Lambdas sind ohne Func<>, Action<> und Predicate<> kaum vorstellbar. Das sind spezielle Delegatetypen:
- Action — gibt nichts zurück.
- Func — gibt einen Wert zurück.
- Predicate — gibt bool zurück, normalerweise für Filterungen.
Beispiel mit Action:
Action<string> log = message => Console.WriteLine(message);
log("Diese Nachricht über ein Lambda!");
Beispiel mit Func:
Func<int, int, int> multiply = (a, b) => a * b;
int product = multiply(3, 5); // 15
Beispiel mit Predicate:
Predicate<int> isNegative = n => n < 0;
bool test = isNegative(-7); // true
6. Lambdas mit mehreren Ausdrücken: wann ein Block nötig ist
Wenn das Lambda mehrere Operationen ausführen soll, verwende geschweifte Klammern und ein explizites return:
Func<int, int, string> describeSum = (a, b) =>
{
int sum = a + b;
return $"Summe: {sum}";
};
Ohne return wird der Compiler meckern (aber nicht immer sehr aussagekräftig — er sagt einfach, dass „nicht alle Pfade einen Wert zurückgeben“).
7. Rückgabe von void: Action
Wenn das Lambda nichts zurückgibt, verwende Action:
Action greet = () => Console.WriteLine("Lächle — der Code kompiliert!");
Ein Lambda kann beliebig viele Anweisungen enthalten:
Action<int> printSquare = x =>
{
int sq = x * x;
Console.WriteLine($"Das Quadrat von {x} ist {sq}");
};
8. Einschränkungen und typische Fehler
Manchmal möchte man sehr frei ein Lambda schreiben, aber der Compiler ist nicht immer einverstanden.
Du darfst keine Variable mit dem gleichen Namen deklarieren wie eine außerhalb gefangene Variable.
Achte auf die Typen: wenn Signatur des Delegates und des Lambdas nicht übereinstimmen — gibt es einen Fehler.
Die Rückgabe eines Wertes ist verpflichtend, wenn der Delegate einen Rückgabewert verlangt.
In komplexen Lambdas vergiss die geschweiften Klammern nicht. Ein Ausdruck — ohne Klammern und ohne return. Mehrere Statements — Klammern und return.
GO TO FULL VERSION