1. Intro
Avant, tu pouvais ajouter aux classes seulement des Extension-methods. Mais ajouter une propriété (property) comme extension de classe, c’était pas possible ! Genre, si tu voulais que chaque DateTime ait une propriété IsWeekend, tu devais passer par une méthode, ce qui n’est pas toujours cool — surtout si tu veux écrire date.IsWeekend au lieu de date.IsWeekend().
Avec la sortie de C# 14, le rêve devient réalité : tu peux maintenant écrire des propriétés d’extension un peu comme les méthodes. Ça te permet d’ajouter une nouvelle propriété à un type existant sans toucher à son code source, et de les utiliser comme si c’était des propriétés normales !
Où c’est vraiment utile ?
- Pour les types standards .NET et les libs externes dont tu ne peux pas modifier le code.
- Pour des propriétés « virtuelles » pratiques dans les view-models, UI, vues calculées.
- Quand tu veux une syntaxe stylée genre .SomeCalculatedProperty sans parenthèses en trop.
2. Nouvelle syntaxe dans C# 14
Dans C# 14, ils ont viré le mot-clé this pour les extensions. À la place, ils ont ajouté un opérateur spécial extension(Type this). Et avec ça, tu peux ajouter de nouveaux membres virtuels à une classe.
Ancienne syntaxe
public static class StringExtensions
{
public static bool IsNullOrWhiteSpace(this string str)
=> string.IsNullOrWhiteSpace(str);
}
Nouvelle syntaxe
public static class Enumerable
{
extension(TSource source)
{
// Membres virtuels pour l’objet
}
extension(TSource)
{
// Membres statiques virtuels
}
}
3. Syntaxe des propriétés d’extension
À quoi ça ressemble ?
Imaginons que tu veux ajouter au type DateTime une propriété qui te dit si la date est un week-end :
public static class DateTimeExtensions
{
public static bool IsWeekend(this DateTime date) =>
date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
}
Mais ça, c’est l’ancienne version Extension Method, et tu l’appelles comme ça : myDate.IsWeekend()
Nouveau style — Extension Property
public static class DateTimeExtensions
{
extension(DateTime source)
{
public bool IsWeekend // propriété d’extension !
{
get => source.DayOfWeek == DayOfWeek.Saturday || source.DayOfWeek == DayOfWeek.Sunday;
}
}
}
Maintenant tu peux écrire :
DateTime today = DateTime.Now;
if (today.IsWeekend)
{
Console.WriteLine("Tu peux dormir plus longtemps !");
}
4. Quels types d’extension properties existent
Tu peux ajouter non seulement des propriétés read-only, mais aussi read-write :
public static class DateTimeExtensions
{
extension(DateTime source)
{
public int YearFrom1900 // propriété d’extension !
{
get => source.Year - 1900;
set => source.Year = value + 1900;
}
}
}
5. Propriétés statiques
Grâce à la nouvelle syntaxe, tu peux ajouter des propriétés virtuelles non seulement à l’objet, mais aussi à la classe ! Oui, t’as bien compris, maintenant on peut ajouter des propriétés statiques virtuelles à une classe. La syntaxe est quasi la même :
public static class DateTimeExtensions
{
// Nouvelle syntaxe : extension block pour DateTime (C# 14)
extension(DateTime)
{
// Propriété statique pour stocker le fuseau horaire courant de l’utilisateur
private static TimeZoneInfo _currentTimeZone = TimeZoneInfo.Local;
// Propriété d’extension pour accéder au fuseau horaire courant
public static TimeZoneInfo CurrentTimeZone
{
get => _currentTimeZone;
set => _currentTimeZone = value ?? TimeZoneInfo.Local;
}
// Retourne l’heure dans le fuseau horaire utilisateur
public DateTime InCurrentTimeZone
{
get => TimeZoneInfo.ConvertTime(this, CurrentTimeZone);
}
}
}
6. Exemples : on étend la classe Dog !
On continue à faire évoluer notre appli avec les chiens, qu’on traîne de conf en conf.
Imaginons que maintenant on a non seulement des chiens, mais aussi une liste de leurs vaccins (List<DateTime>), mais la classe Dog vient d’une lib externe, donc on ne peut pas toucher à son code. On veut ajouter une propriété : Est-ce que tous les vaccins nécessaires ont été faits cette année ?
Ancienne méthode (extension method) :
public static class DogExtensions
{
public static bool AllVaccinatedThisYear(this Dog dog)
{
return dog.Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
// Utilisation :
if (myDog.AllVaccinatedThisYear())
Console.WriteLine("Le chien est en bonne santé !");
Nouvelle méthode (propriété d’extension) :
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// Utilisation :
if (myDog.AllVaccinatedThisYear)
Console.WriteLine("Le chien est en bonne santé !");
Exemple complet
// Classe Dog — par exemple, d’une lib externe :
public class Dog
{
public string Name { get; set; }
public List<DateTime> Vaccinations { get; set; } = new List<DateTime>();
}
// Classe d’extensions avec extension block :
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// Dans le programme :
var myDog = new Dog { Name = "Buddy" };
myDog.Vaccinations.Add(new DateTime(DateTime.Now.Year, 2, 16)); // vaccin cette année
Console.WriteLine($"{myDog.Name}: vacciné ? {(myDog.AllVaccinatedThisYear ? "Oui" : "Non")}");
7. Tableau : Extension methods vs Extension properties
| Extension method | Extension property | |
|---|---|---|
| Syntaxe d’appel | obj.Method() | obj.Property |
| Passe des paramètres | Oui | Non (juste this obj) |
| Peut être assignée | Non applicable | Seulement si implémenté |
| Pratique pour View/UI | Parfois | Oui (binding bidirectionnel, lambda) |
| Visible en réflexion | Non | Non |
8. Pièges potentiels et erreurs classiques
Quand les extension properties ne servent à rien
- Elles ne peuvent pas remplacer complètement les vrais champs : elles n’ont pas accès aux membres privés de l’objet.
- Impossible d’ajouter un changement automatique d’état de l’objet (genre, tu ne peux pas suivre le changement de valeur dans la classe d’origine direct).
- Impossible d’utiliser une extension property pour implémenter une interface ou une classe abstraite.
Erreur de nommage
Si jamais la classe d’origine reçoit une propriété avec le même nom que la tienne, c’est la propriété « native » qui sera utilisée, pas ton extension. Donc fais gaffe au choix des noms, surtout avec les types publics de .NET.
Problèmes de sérialisation/réflexion
Une extension property, ce n’est pas un « vrai » membre du type, juste du sucre syntaxique. Donc, si tu utilises la réflexion ou la sérialisation, la propriété d’extension risque de ne pas être visible pour ces outils.
GO TO FULL VERSION