Funktionale Programmierung in C#: von A bis Z
Funktionale Programmierung (FP) ist ein Paradigma, das Berechnungen als Auswertung mathematischer Funktionen betrachtet und veränderlichen Zustand sowie Seiteneffekte vermeidet. Obwohl C# eine multiparadigmatische Sprache mit starker Unterstützung für objektorientierte Programmierung (OOP) ist, integrieren seine modernen Versionen (ab C# 3.0 und höher) aktiv Elemente des funktionalen Stils. Dies ermöglicht es, prägnanteren, vorhersagbareren und leichter testbaren Code zu schreiben.
In diesem Artikel gehen wir den Weg von den Grundlagen bis zu fortgeschrittenen Techniken der funktionalen Programmierung in C# im Kontext von .NET. Sie erfahren, wie Sie Lambda-Ausdrücke, LINQ, unveränderliche Datentypen und Muster verwenden, um robuste Anwendungen zu erstellen.
1. Grundlagen: Lambda-Ausdrücke und Delegaten
Das Herz des funktionalen Ansatzes in C# sind Lambda-Ausdrücke – anonyme Funktionen, die zum Erstellen von Delegaten oder Ausdrucksbäumen verwendet werden können. Sie ermöglichen es, Verhalten als Daten zu übergeben.
Betrachten wir ein klassisches Beispiel für das Sortieren einer Liste. Anstatt eine separate Vergleichsmethode zu erstellen, verwenden wir ein Lambda:
using System;using System.Collections.Generic;
public class LambdaExample{ public static void Main() { var numbers = new List<int> { 5, 3, 8, 1, 9 }; // Absteigend sortieren mit einem Lambda-Ausdruck numbers.Sort((x, y) => y.CompareTo(x)); Console.WriteLine(string.Join(", ", numbers)); // Ausgabe: 9, 8, 5, 3, 1 }}Wichtige Konzepte, die hier wirken:
- Delegaten
Func<>undAction<>:Func<T, TResult>gibt einen Wert zurück,Action<T>nicht. Lambdas werden implizit in diese Typen konvertiert. - Closures (Schließungen): Ein Lambda kann Variablen aus dem äußeren Gültigkeitsbereich erfassen, was es zu einem mächtigen Werkzeug macht, aber aufgrund möglicher Seiteneffekte Vorsicht erfordert.
2. LINQ: Deklarativer Stil für die Datenverarbeitung
Language Integrated Query (LINQ) ist wohl das bekannteste Beispiel für die Anwendung von FP in C#. Es ermöglicht das Schreiben deklarativer Abfragen für Sammlungen, Datenbanken und XML mithilfe von Methodenverkettungen.
Anstelle imperativer foreach-Schleifen verwenden wir funktionale Operationen:
using System;using System.Linq;using System.Collections.Generic;
public class LinqExample{ public static void Main() { var people = new List<Person> { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 17 }, new Person { Name = "Charlie", Age = 25 } };
// Funktionale Abfrage: Filtern, Projizieren, Sortieren var result = people .Where(p => p.Age >= 18) // Filtern (Prädikat) .OrderBy(p => p.Name) // Sortieren .Select(p => new { p.Name, IsAdult = true }) // Projektion (anonymer Typ) .ToList();
foreach (var item in result) { Console.WriteLine($"{item.Name} - Adult: {item.IsAdult}"); } // Ausgabe: Alice - Adult: True, Charlie - Adult: True }
public class Person { public string Name { get; set; } public int Age { get; set; } }}Wichtige LINQ-Operatoren:
Where– Filtern (Analogon zufilter).Select– Transformation (Analogon zumap).Aggregate– Faltung (Analogon zureduce).Any,All– Bedingungsprüfung.
Es ist wichtig, die verzögerte Ausführung zu beachten.