Extension Properties in C#: Wenn man will, aber nicht kann (und wie man es umgeht)
Stellen Sie sich vor: Sie arbeiten mit einer Bibliothek, in der die Klasse Person eine Eigenschaft FullName hat. Alles gut, aber leider müssen Sie eine berechnete Eigenschaft AgeInDays hinzufügen, die das Alter in Tagen ab dem Geburtsdatum berechnet. Sie sind an Extension Methods gewöhnt und denken: "Warum nicht auch Extension Properties?"
Und dann gehen Sie auf Stack Overflow, sehen eine Frage mit tausenden Aufrufen: "Does C# have extension properties?" — und lesen enttäuscht die Antwort: "Nein, werden offiziell nicht unterstützt". Aber schließen Sie den Tab nicht! In diesem Artikel analysieren wir nicht nur, warum es sie nicht gibt, sondern finden auch elegante Umgehungsmöglichkeiten, die in puncto Leistung nicht nachstehen.
Warum fügt C# keine Extension Properties hinzu? Historischer Kontext
Beginnen wir mit dem Wichtigsten: Extension Properties sind keine Laune, sondern eine langjährige Anfrage der Community. Bereits 2016 gab es einen Vorschlag auf GitHub (C# feature request), aber er wurde bisher nicht umgesetzt. Warum?
- Komplexität mit dem Compiler: Im Gegensatz zu Methoden haben Eigenschaften Getter und Setter, die an eine bestimmte Instanz gebunden sein müssen. Eine Erweiterung dieser Logik auf Syntaxebene erfordert erhebliche Änderungen am Compiler.
- Konflikt mit Indexern: Eigenschaften und Indexer sind in C# eng miteinander verbunden. Das Hinzufügen von Extension Properties könnte zu Mehrdeutigkeiten führen.
- Priorität anderer Features: Das C#-Team konzentrierte sich auf Records, Pattern Matching und Static Abstract Members (C# 11), die für die meisten Szenarien mehr Nutzen bringen.
Aber das Fehlen offizieller Unterstützung ist kein Todesurteil. Schauen wir uns an, wie erfahrene Entwickler diese Aufgabe lösen.
Extension Methods: Ihr wichtigstes Werkzeug (aber mit Nuancen)
Der naheliegendste Weg ist die Verwendung von Extension Methods anstelle von Eigenschaften. Statt person.AgeInDays schreiben Sie person.GetAgeInDays(). Das funktioniert, verletzt aber das Prinzip der Einheitlichkeit: Im restlichen Code verwenden Sie Eigenschaften, und hier plötzlich eine Methode.
public static class PersonExtensions{ public static int GetAgeInDays(this Person person) { return (DateTime.Now - person.BirthDate).Days; }}
// Verwendung:var age = person.GetAgeInDays(); // Funktioniert, aber nicht schönNachteil: Der Code wird weniger lesbar, besonders in LINQ-Aufrufketten. Vorteil: Es ist aus Leistungssicht völlig kostenlos – der Aufruf einer Extension Method unterscheidet sich nicht von einer normalen statischen Methode.
Alternative Nr. 1: Statische Fabriken und Hilfsklassen
Wenn Sie eine "Eigenschaft" benötigen, die auf Basis von Daten berechnet wird, können Sie eine statische Helper-Klasse erstellen:
public static class PersonHelper{ public static int AgeInDays(Person person) => (DateTime.Now - person.BirthDate).Days;}
// Verwendung:var age = PersonHelper.AgeInDays(person);Das ist ehrlicher als eine Extension Method: Man sieht sofort, dass es sich um eine Hilfsfunktion handelt. Aber immer noch keine Eigenschaft.
Alternative Nr. 2: Attribute und Codegenerierung (Source Generators)
Für komplexe Szenarien (z.B. Hinzufügen von Eigenschaften zu Klassen aus NuGet-Paketen) können Sie Source Generators verwenden. Sie wurden in .NET 5 eingeführt und ermöglichen die Codegenerierung während der Kompilierung. Sie schreiben ein Attribut, und der Generator erstellt eine partial-Klasse mit den gewünschten Eigenschaften.
[AutoExtensionProperty(typeof(Person), nameof(Person.BirthDate))]public partial class PersonExtensions{ // Der Generator erstellt die Eigenschaft AgeInDays}
// Generierter Code:public partial class PersonExt