Funktionale Programmierung in C#: Prinzipien und Beispiele

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Funktionale Programmierung in C#: Von der Theorie zur Praxis

Funktionale Programmierung (FP) ist ein Paradigma, bei dem Berechnungen als Auswertung mathematischer Funktionen betrachtet werden, wobei Zustandsänderungen und veränderliche Daten vermieden werden. Obwohl C# ursprünglich eine objektorientierte Sprache war, hat es ab Version 3.0 aktiv funktionale Möglichkeiten aufgenommen. Heute unterstützt C# Konzepte wie Lambda-Ausdrücke, LINQ, unveränderliche Typen und sogar Pattern Matching. In diesem Artikel werden wir die wichtigsten Prinzipien der FP erläutern und zeigen, wie man sie in realen C#-Projekten anwendet.



1. Reine Funktionen und das Fehlen von Seiteneffekten

Eine reine Funktion ist eine Funktion, die:

  • Für dieselben Argumente immer dasselbe Ergebnis zurückgibt (referenzielle Transparenz).
  • Keine Seiteneffekte hat (keinen globalen Zustand ändert, nicht in Dateien schreibt, keine HTTP-Anfragen sendet).

In C# kann eine reine Funktion so aussehen:

public static int Add(int a, int b) => a + b;

Und hier ein Beispiel für eine unreine Funktion:

public static int AddAndLog(int a, int b){    Console.WriteLine($"Addiere {a} und {b}"); // Seiteneffekt    return a + b;}

Vorteile reiner Funktionen: Sie sind leicht zu testen, zu debuggen und zu parallelisieren.



2. Unveränderlichkeit (Immutability)

In der FP sind Daten standardmäßig unveränderlich. In C# werden dafür verwendet:

  • Das Schlüsselwort readonly für Felder.
  • record-Strukturen (C# 9+), die automatisch unveränderliche Objekte erstellen.
  • Sammlungen aus dem Namespace System.Collections.Immutable.

Beispiel mit record:

public record Person(string Name, int Age);

Wenn das Alter geändert werden muss, wird eine neue Instanz erstellt:

Person person = new("Ivan", 30);Person olderPerson = person with { Age = 31 };

Unveränderlichkeit verhindert versehentliche Mutationen und vereinfacht die Multithreading-Programmierung.



3. Funktionen höherer Ordnung und Lambda-Ausdrücke

Funktionen höherer Ordnung nehmen andere Funktionen als Argumente entgegen oder geben sie zurück. In C# wird dies durch Delegaten realisiert: Func<>, Action<>, Predicate<>.

Ein einfaches Beispiel ist die Where-Methode aus LINQ:

List<int> numbers = new() { 1, 2, 3, 4, 5 };var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

Hier ist n => n % 2 == 0 ein Lambda-Ausdruck (eine anonyme Funktion).

Man kann seine eigene Funktion höherer Ordnung schreiben:

public static List<T> Filter<T>(List<T> list, Func<T, bool> predicate){    var result = new List<T>();    foreach (var item in list)        if (predicate(item)) result.Add(item);    return result;}


4. LINQ: Ein mächtiges Werkzeug des funktionalen Stils

LINQ (Language Integrated Query) ist wohl das bekannteste Beispiel für funktionale Programmierung in C#. Es ermöglicht die deklarative Verarbeitung von Sammlungen, ähnlich wie in SQL.

Beispiel: Namen von Benutzern über 18 Jahren abrufen, sortiert nach Alter:

var users = new List<User>{    new("Anna", 22),    new("Boris", 17),    new("Viktor", 30)};

var result = users .Where(u => u.Age >= 18) .OrderBy(u => u.Age) .Select(u => u.Name) .ToList();

LINQ unterstützt verzögerte Ausführung (lazy evaluation), was Ressourcen spart.



5. Monaden und der Maybe-Typ in C#

Monaden sind eine Abstraktion für Berechnungsketten mit Kontext (z. B. Behandlung von null oder Asynchronität). C# hat keine eingebaute Maybe-Monade, aber sie ist leicht zu implementieren:

public class Maybe<T>{    private readonly T _value;    public bool HasValue { get; }        p                

Blogs

Buchempfehlungen