Kurz: Ein Delegate ist ein Typ für Methoden. Wichtigste fertige Delegates: Action (ohne Rückgabe), Func<…> (mit Rückgabe), Predicate<T> (liefert bool).
Teil des Kurses C#
Delegates und Lambdas
Ein Delegate ist ein Typ für Methoden. Wichtigste fertige Delegates: Action (ohne Rückgabe), Func<...> (mit Rückgabe), Predicate<T> (liefert bool).
Func<int, int> quadrat = x => x * x;
Func<int, int, int> plus = (a, b) => a + b;
Action<string> ausgabe = s => Console.WriteLine("> " + s);
Predicate<string> leer = string.IsNullOrEmpty;
ausgabe($"{quadrat(7)} {plus(3, 4)} {leer("")}");
int faktor = 10;
Func<int, int> mal = x => x * faktor; // Closure: fängt faktor ein
faktor = 3;
Console.WriteLine(mal(5));
Func<int, Func<int, int>> addierer = a => b => a + b; // Funktion, die eine Funktion liefert
var plus5 = addierer(5);
Console.WriteLine(plus5(10));
var woerter = new List<string> { "Birne", "Apfel", "Kiwi" };
woerter.Sort((a, b) => a.Length.CompareTo(b.Length));
woerter.ForEach(w => Console.Write(w + " "));
Console.WriteLine();
static int Rechne(Func<int, int, int> op, int a, int b) => op(a, b);
Console.WriteLine($"{Rechne((a, b) => a * b, 6, 7)} {Rechne(Math.Max, 3, 9)}"); // Methodengruppe als DelegateAusgabe:
> 49 7 True
15
15
Kiwi Apfel Birne
42 9Lambdas fangen Variablen per Referenz ein: Änderungen von außen wirken sich aus (mal(5) ergibt 15, nicht 50).
Events
Ein Event erlaubt einer Klasse, andere über etwas zu informieren (Beobachter-Muster):
var knopf = new Knopf();
knopf.Geklickt += (sender, e) => Console.WriteLine($"Handler 1: Klick Nr. {e.Nummer}");
knopf.Geklickt += (sender, e) => Console.WriteLine($"Handler 2: {e.Nummer * 10}");
knopf.Klicken();
knopf.Klicken();
class KlickArgs(int nummer) : EventArgs
{
public int Nummer { get; } = nummer;
}
class Knopf
{
public event EventHandler<KlickArgs>? Geklickt; // nur die Klasse selbst löst aus
private int _zaehler;
public void Klicken() => Geklickt?.Invoke(this, new KlickArgs(++_zaehler));
}Ausgabe:
Handler 1: Klick Nr. 1
Handler 2: 10
Handler 1: Klick Nr. 2
Handler 2: 20Außen kann man sich nur an- und abmelden (+=, -=); nur die Klasse löst das Event aus. ?.Invoke verhindert einen Fehler, falls niemand zuhört. Vergiss das Abmelden (-=) nicht, sonst hält der Sender den Empfänger am Leben (Speicherleck).
Funktionen als Daten
var befehle = new Dictionary<string, Func<double, double, double>>
{
["+"] = (a, b) => a + b,
["-"] = (a, b) => a - b,
["*"] = (a, b) => a * b,
["/"] = (a, b) => b == 0 ? double.NaN : a / b,
};
foreach (var (zeichen, op) in befehle) Console.Write($"8 {zeichen} 2 = {op(8, 2)} ");
Console.WriteLine();
Func<int, bool>[] regeln = [x => x > 0, x => x % 2 == 0, x => x < 100];
Console.WriteLine(regeln.All(r => r(42)) + " " + regeln.All(r => r(101)));Ausgabe:
8 + 2 = 10 8 - 2 = 6 8 * 2 = 16 8 / 2 = 4
True FalseMehrere Delegates verketten
Action a = () => Console.Write("A ");
a += () => Console.Write("B ");
a += () => Console.Write("C ");
a();
Console.WriteLine();Ausgabe:
A B CMerke
Func<..., R>,Action<...>undPredicate<T>decken fast alle Delegate-Fälle ab- Lambdas
(a, b) => a + bfangen Variablen ihrer Umgebung ein (Closure) - Events (
event EventHandler<T>) benachrichtigen Beobachter:+=zum Anmelden,-=zum Abmelden - Funktionen lassen sich in Variablen, Listen und Dictionaries speichern
Übungsaufgabe
Baue eine Klasse Thermostat mit einem Event TemperaturGeaendert, das beim Setzen eines neuen Wertes ausgelöst wird.
Quiz zur Selbstkontrolle
Was ist Func<int, int>?
- Ein Delegate für eine Funktion mit int-Parameter und int-Rückgabe (richtig)
- Eine Klasse
- Ein Datentyp für Ganzzahlen
- Ein Fehler
Wie meldet man sich an einem Event an?
- event += handler (richtig)
- event = handler
- event.Add(handler)
- event.Subscribe()
Was fängt eine Closure ein?
- Variablen aus der Umgebung, in der das Lambda entsteht (richtig)
- Alle Ausnahmen
- Alle Parameter der Methode
- Nichts
Weiter im Kurs
Zurück: Generics und LINQ
Weiter: Asynchrone Programmierung mit async/await
Alle Kapitel: C# im Überblick