1. Einführung
Früher konntest du Klassen nur Extension-Methoden hinzufügen. Aber eine Property (property) als Erweiterung ging nicht! Wenn du also wolltest, dass z.B. jeder DateTime eine Property IsWeekend bekommt, musstest du das als Methode machen – was nicht immer praktisch ist, vor allem wenn du lieber date.IsWeekend statt date.IsWeekend() schreiben willst.
Mit C# 14 ist der Traum wahr geworden: Jetzt kannst du Extension Properties fast wie Methoden schreiben. Damit kannst du einem bestehenden Typ eine neue Property hinzufügen, ohne den Originalcode zu ändern – und du benutzt sie wie eine ganz normale Property!
Wo ist das wirklich nützlich?
- Für Standardtypen aus .NET und externe Bibliotheken, deren Code du nicht ändern kannst.
- Für praktische „virtuelle“ Properties in ViewModels, UI, berechneten Views.
- Überall, wo du einen schönen Syntax wie .SomeCalculatedProperty ohne Klammern willst.
2. Neuer Syntax in C# 14
In C# 14 wurde das Schlüsselwort this für Erweiterungen abgeschafft. Stattdessen gibt es jetzt den speziellen Operator extension(Type this). Damit kannst du neue virtuelle Members zu einer Klasse hinzufügen.
Alter Syntax
public static class StringExtensions
{
public static bool IsNullOrWhiteSpace(this string str)
=> string.IsNullOrWhiteSpace(str);
}
Neuer Syntax
public static class Enumerable
{
extension(TSource source)
{
// Virtuelle Members für das Objekt
}
extension(TSource)
{
// Virtuelle statische Members
}
}
3. Syntax für Extension Properties
Wie sieht das aus?
Angenommen, du willst dem Typ DateTime eine Property hinzufügen, die zurückgibt, ob das Datum ein Wochenende ist:
public static class DateTimeExtensions
{
public static bool IsWeekend(this DateTime date) =>
date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
}
Aber das ist der alte Weg mit Extension Method, und du rufst es so auf: myDate.IsWeekend()
Neuer Stil – Extension Property
public static class DateTimeExtensions
{
extension(DateTime source)
{
public bool IsWeekend // Extension Property!
{
get => source.DayOfWeek == DayOfWeek.Saturday || source.DayOfWeek == DayOfWeek.Sunday;
}
}
}
Jetzt kannst du so schreiben:
DateTime today = DateTime.Now;
if (today.IsWeekend)
{
Console.WriteLine("Du kannst länger schlafen!");
}
4. Welche Extension Properties gibt es?
Du kannst nicht nur read-only Properties hinzufügen, sondern auch read-write:
public static class DateTimeExtensions
{
extension(DateTime source)
{
public int YearFrom1900 // Extension Property!
{
get => source.Year - 1900;
set => source.Year = value + 1900;
}
}
}
5. Statische Properties
Mit dem neuen Syntax kannst du virtuelle Properties nicht nur dem Objekt, sondern auch der Klasse hinzufügen! Ja, richtig gelesen: Jetzt kannst du virtuelle statische Properties zu einer Klasse hinzufügen. Der Syntax ist fast gleich:
public static class DateTimeExtensions
{
// Neuer Syntax: extension block für DateTime (C# 14)
extension(DateTime)
{
// Statische Property für die aktuelle Zeitzone des Users
private static TimeZoneInfo _currentTimeZone = TimeZoneInfo.Local;
// Extension Property für Zugriff auf die aktuelle Zeitzone
public static TimeZoneInfo CurrentTimeZone
{
get => _currentTimeZone;
set => _currentTimeZone = value ?? TimeZoneInfo.Local;
}
// Gibt die Zeit in der User-Zeitzone zurück
public DateTime InCurrentTimeZone
{
get => TimeZoneInfo.ConvertTime(this, CurrentTimeZone);
}
}
}
6. Beispiele: Wir erweitern die Klasse Dog!
Lass uns weiter an unserer Hunde-App basteln, die wir schon seit mehreren Vorlesungen pflegen.
Angenommen, wir haben jetzt nicht nur Hunde, sondern auch eine Liste ihrer Impfungen (List<DateTime>), aber die Klasse Dog kommt aus einer externen Bibliothek und wir können den Code nicht ändern. Wir wollen eine Property hinzufügen: Sind alle nötigen Impfungen dieses Jahr gemacht?
Alter Weg (Extension Method):
public static class DogExtensions
{
public static bool AllVaccinatedThisYear(this Dog dog)
{
return dog.Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
// Verwendung:
if (myDog.AllVaccinatedThisYear())
Console.WriteLine("Der Hund ist gesund!");
Neuer Weg (Extension Property):
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// Verwendung:
if (myDog.AllVaccinatedThisYear)
Console.WriteLine("Der Hund ist gesund!");
Komplettes Beispiel
// Klasse Dog – z.B. aus einer externen Bibliothek:
public class Dog
{
public string Name { get; set; }
public List<DateTime> Vaccinations { get; set; } = new List<DateTime>();
}
// Erweiterungsklasse mit extension block:
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// Im Programm:
var myDog = new Dog { Name = "Buddy" };
myDog.Vaccinations.Add(new DateTime(DateTime.Now.Year, 2, 16)); // Impfung dieses Jahr
Console.WriteLine($"{myDog.Name}: geimpft? {(myDog.AllVaccinatedThisYear ? "Ja" : "Nein")}");
7. Tabelle: Extension Methods vs Extension Properties
| Extension Method | Extension Property | |
|---|---|---|
| Aufruf-Syntax | obj.Method() | obj.Property |
| Parameter übergeben | Ja | Nein (nur this obj) |
| Kann geschrieben werden | Nicht anwendbar | Nur wenn implementiert |
| Praktisch für View/UI | Manchmal | Ja (Two-way Bindings, Lambda) |
| Sichtbar in Reflection | Nein | Nein |
8. Potenzielle Fallen und typische Fehler
Wann Extension Properties nicht helfen
- Sie können keine echten Felder ersetzen: Sie haben keinen Zugriff auf private Members des Objekts.
- Du kannst kein automatisches Ändern des Objektzustands hinzufügen (z.B. kannst du Wertänderungen im Original-Klasse nicht direkt berücksichtigen).
- Du kannst Extension Properties nicht für die Implementierung eines Interface oder einer abstrakten Klasse nutzen.
Namenskonflikt-Fehler
Falls die Originalklasse plötzlich eine Property mit dem gleichen Namen wie deine bekommt, wird die „native“ Property benutzt, nicht deine Erweiterung. Sei also vorsichtig bei der Namenswahl, besonders bei öffentlichen .NET-Typen.
Probleme mit Serialisierung/Reflection
Extension Properties sind kein „echtes“ Member des Typs, sondern nur syntaktischer Zucker. Wenn irgendwo Reflection oder Serialisierung genutzt wird, kann die Extension Property für solche Tools unsichtbar sein.
GO TO FULL VERSION