C# Delegate Func Action einfach erklärt: So funktionieren sie
Delegates, Func und Action in C# kompakt erklärt: Verstehe, was Methodenverweise sind und wie du sie für flexiblen Code einsetzt.
By Marcel Schmidtpeter 25 Sept 2026 Stell dir vor, du sitzt in deinem ersten Berufsmonat als Fachinformatiker und sollst eine Methode schreiben, die eine Liste von Kundendaten verarbeitet. Mal soll gefiltert werden, mal sortiert, mal soll etwas ausgegeben werden. Dein Ausbilder sagt nur: „Übergib die Logik doch als Parameter." Für viele Einsteiger endet das in Fragezeichen - genau hier kommen Delegates, Func und Action in C# ins Spiel.
Was ist ein Delegate in C#?
Ein Delegate ist ein Typ, der eine Methode als Variable speichern kann. Stell dir ein Delegate wie eine Steckdose vor: Die Steckdose legt fest, welcher Stecker (welche Methodenform) passt - zum Beispiel „nimmt zwei Zahlen, gibt eine Zahl zurück". Jede Methode mit passender Form kannst du einstecken und aufrufen.
// Delegate-Deklaration: definiert die "Form" der Methode
public delegate int Berechne(int a, int b);
class Program
{
static void Main()
{
// Methode in einer Variable speichern
Berechne addiere = Addieren;
int ergebnis = addiere(3, 4); // ergibt 7
}
static int Addieren(int a, int b)
{
return a + b;
}
}Warum braucht man das? Weil Methoden dadurch Werte werden, die du übergeben kannst - an andere Methoden, in Listen oder als Rückgabewert. Die offizielle Einführung dazu findest du bei Microsoft Learn.
Merke: Ein Delegate ist ein Typ für Methoden. Es legt fest, welche Parameter eine Methode haben muss und was sie zurückgibt.
Was ist Func<T, TResult>?
Func ist ein fertiges Delegate aus dem .NET Framework für Methoden mit Rückgabewert. Du musst also kein eigenes Delegate mehr deklarieren - das nimmt dir `Func` ab. Der letzte Typparameter ist immer der Rückgabetyp, alle davor sind die Parameter.
// Func<Parameter..., Rueckgabetyp>
Func<int, int, int> multipliziere = (a, b) => a * b;
Func<string, int> laenge = s => s.Length;
int produkt = multipliziere(4, 5); // 20
int zeichen = laenge("Hallo"); // 5`Func<int, int, int>` bedeutet: zwei `int`-Parameter rein, ein `int` raus. Du kannst bis zu 16 Parameter verwenden - das reicht im Alltag fast immer. Die Schreibweise `(a, b) => a * b` ist übrigens ein Lambda-Ausdruck, den ich in einem eigenen Artikel zu C# Lambda Expressions genauer erkläre. Die API-Referenz zu `Func` findest du ebenfalls bei Microsoft Learn.
Was ist Action<T>?
Action ist das Gegenstück zu `Func` - für Methoden ohne Rückgabewert (also `void`). Alle Typparameter sind Parameter, ein Rückgabetyp fehlt.
// Action<Parameter...> - gibt nichts zurueck
Action<string> begruessung = name => Console.WriteLine("Hallo, " + name + "!");
Action meldung = () => Console.WriteLine("Fertig!");
begruessung("Alex"); // Ausgabe: Hallo, Alex!
meldung(); // Ausgabe: Fertig!Details dazu stehen in der Dokumentation zu Action<T>;.
Func, Action und Predicate im Vergleich
Alle drei sind vordefinierte Delegates. Der Unterschied liegt allein im Rückgabewert:
Typ | Rückgabewert | Typische Verwendung | Beispiel |
`Func<T, TResult>` | Beliebig (letzter Typparameter) | Berechnungen, Transformationen | `Func<int, bool>` |
`Action<T>` | `void` (keiner) | Nebenwirkungen, Ausgaben | `Action<string>` |
`Predicate<T>` | Immer `bool` | Prüfungen, Filter | `Predicate<int>` |
Merke: `Func` gibt etwas zurück, `Action` gibt nichts zurück, `Predicate` gibt immer `bool` zurück. In neuem Code verwendet man meist `Func<T, bool>` statt `Predicate<T>` - beide sind austauschbar.
Wie übergibst du Methoden als Parameter?
Jetzt ein vollständiges Beispiel, wie es dir im Betrieb oder in der Prüfung begegnen kann. Wir bauen eine Verarbeitungsmethode für Noten, der du die Logik selbst übergibst:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> noten = new List<int> { 2, 4, 1, 5, 3, 2 };
// Func als Filter uebergeben
List<int> guteNoten = Filtern(noten, n => n <= 2);
Console.WriteLine("Gute Noten: " + string.Join(", ", guteNoten));
// Action als Ausgabe-Logik uebergeben
Verarbeiten(noten, n => Console.WriteLine("Note: " + n));
}
// Nimmt eine Methode entgegen, die int in bool umwandelt
static List<int> Filtern(List<int> liste, Func<int, bool> kriterium)
{
List<int> ergebnis = new List<int>();
foreach (int element in liste)
{
if (kriterium(element))
{
ergebnis.Add(element);
}
}
return ergebnis;
}
// Nimmt eine Methode entgegen, die nichts zurueckgibt
static void Verarbeiten(List<int> liste, Action<int> aktion)
{
foreach (int element in liste)
{
aktion(element);
}
}
}Kernidee: Du übergibst nicht das Ergebnis einer Methode, sondern die Methode selbst. Die aufgerufene Methode entscheidet dann selbst, was sie mit jedem Element tut.
Genau nach diesem Prinzip funktioniert übrigens LINQ - `liste.Where(n => n <= 2)` macht intern nichts anderes als unser `Filtern`.
Häufige Fehler bei Delegates, Func und Action
1. Rückgabetyp bei Func vergessen
Du willst eine Methode speichern, die einen `int` nimmt und `bool` zurückgibt - und schreibst `Func<bool>`? Dann fehlt der Parameter. Der letzte Typparameter ist immer der Rückgabetyp, auch wenn die Methode keine Parameter hat:
// Falsch: hat keinen Parameter — note <= 2 braucht aber einen
Func<bool> falsch;
// Richtig: ein int-Parameter, bool als Rueckgabetyp
Func<int, bool> istBestanden = note => note <= 2;2. Delegate ist null und wird trotzdem aufgerufen
Rufst du ein Delegate auf, dem nie eine Methode zugewiesen wurde, knallt eine NullReferenceException:
Action<string> ausgabe = null;
// ausgabe("Test"); // NullReferenceException!
// Sicherer: Pruefen vor dem Aufruf
if (ausgabe != null)
{
ausgabe("Test");
}
// Kuerzer: der null-bedingte Operator
ausgabe?.Invoke("Test");`ausgabe?.Invoke("Test")` führt den Aufruf nur aus, wenn das Delegate nicht `null` ist - das ist die moderne, kürzere Variante.
3. Action und Func verwechseln
Willst du etwas zurückgeben, brauchst du `Func`. Falle: Bei Lambdas, deren Rumpf ein Methodenaufruf ist, kompiliert die Zuweisung zu `Action` sogar - aber der Rückgabewert wird stillschweigend verworfen. Das führt zu schwer findbaren Logikfehlern:
List<string> namen = new List<string> { "Alex", "Kim" };
// Kompiliert — aber das bool-Ergebnis von Remove geht verloren
Action<string> entfernen = name => namen.Remove(name);
// Richtig, wenn du wissen willst, ob etwas entfernt wurde
Func<string, bool> entfernenMitErgebnis = name => namen.Remove(name);Übungstipp: Bau dir einen Mini-Workflow
Nimm dir 15 Minuten und schreibe eine Methode `Ausfuehren(Action schritt1, Action schritt2)`, die zwei Arbeitsschritte nacheinander ausführt. Übergib dann verschiedene Kombinationen per Lambda - zum Beispiel „Datei lesen" und „Ergebnis ausgeben". Warum funktioniert das? Weil `Action` jede Methode aufnimmt, die keine Parameter hat und nichts zurückgibt - die Form muss passen. Das Trainingsprinzip dahinter passt auch zu meinem Tipp, Code handschriftlich zu üben: Schreib die Signaturen erst auf Papier, tippe sie dann ab.
FAQ: Häufige Fragen zu C# Delegates, Func und Action
Was ist der Unterschied zwischen Func und Action?
`Func<T, TResult>` besitzt einen Rückgabewert (letzter Typparameter), `Action<T>` gibt nichts zurück (`void`). Beide sind generische Delegates aus dem .NET Framework.
Was ist ein Delegate einfach erklärt?
Ein Delegate ist ein Typ, der Methoden referenziert. Damit kannst du Methoden wie Werte in Variablen speichern und als Parameter an andere Methoden übergeben - vergleichbar mit Funktionszeigern in C, aber typsicher.
Brauche ich heute noch eigene Delegates?
Selten. Für fast alle Fälle reichen `Func`, `Action` und `Predicate`. Eigene Delegates lohnen sich nur, wenn du einen aussagekräftigen Namen willst oder Events definierst.
Was sind Multicast-Delegates?
Ein Delegate kann mehrere Methoden gleichzeitig halten. Mit `+=` hängst du eine Methode an, mit `-=` entfernst du sie. Beim Aufruf werden alle Methoden der Reihe nach ausgeführt - genau so funktionieren Events.
Was haben Delegates mit async/await zu tun?
Asynchrone Methoden geben `Task`-Objekte zurück und nutzen häufig `Func`-Delegates, etwa bei `Task.Run(() => Berechnung())`. Mehr dazu in meinem Artikel zu C# async await und Task.
Fazit
Delegates sind der Schlüssel, um Methoden als Bausteine zu behandeln - und mit `Func` (mit Rückgabewert) und `Action` (ohne Rückgabewert) hast du zwei fertige Werkzeuge, die du sofort einsetzen kannst. Merk dir nur die eine Regel: Der letzte Typparameter bei `Func` ist immer der Rückgabetyp. Sobald dir das in Fleisch und Blut übergegangen ist, verstehst du auch LINQ, Events und Callbacks auf einen Schlag.
Wenn du bei C# oder einem anderen IT-Thema festhängst - ob für die IHK-Abschlussprüfung, das Studium oder den Berufseinstieg - hol dir individuelle Unterstützung bei study-it.education.
Need someone to walk through this with you?
Instead of re-reading: 30 min with a senior dev.
Book a free first chat →
Delegates, Func und Action in C# kompakt erklärt: Verstehe, was Methodenverweise sind und wie du sie für flexiblen Code einsetzt.
marcel.schmidtpeter@study-it.education →More reading
C# JSON mit System.Text.Json lesen & schreiben – einfach erklärt
JSON-Daten in C# lesen und schreiben? Mit System.Text.Json gelingt dir Serialisierung & Deserialisierung – einfach erklärt für alle IT-Einsteiger.
C# xUnit Unit Test: So schreibst du deine ersten Unit Tests
Unit Tests mit xUnit machen deinen C#-Code belastbar. In diesem Tutorial lernst du [Fact], [Theory] und Assert kennen – für Einsteiger erklärt.
C# Datenbank verbinden: ADO.NET & Entity Framework einfach erklärt
So greifst du aus C# auf Datenbanken zu: mit ADO.NET für direktes SQL oder EF Core als modernem ORM – beide Wege mit Beispielen erklärt.