CodeGym /Cours /C# SELF /Membres d’extension : méthodes

Membres d’extension : méthodes

C# SELF
Niveau 18 , Leçon 2
Disponible

1. Introduction

Dans le monde de la programmation orientée objet, on se retrouve souvent à vouloir ajouter de la nouvelle fonctionnalité à des classes déjà existantes. Parfois, on n’a pas accès au code source de ces classes (genre les types standards .NET, des classes de libs externes ou du code généré).

Dans ces cas-là, les Extension Methods viennent à la rescousse — c’est une feature puissante et élégante du langage C# qui te permet d’« ajouter » des méthodes à des types existants, sans les modifier directement.

Les extension methods, c’est du sucre syntaxique en C# qui te permet d’appeler des méthodes statiques comme si c’était des méthodes d’instance du type. Elles ressemblent et s’utilisent comme si elles avaient toujours fait partie du type, alors qu’en vrai, non.

Imaginons que t’as besoin d’une méthode qui met la première lettre d’une string en majuscule :


public static class StringUtil
{
    public static string CapitalizeFirstLetter(string str)
    {
        if (string.IsNullOrEmpty(str)) return str;
        return char.ToUpper(str[0]) + str.Substring(1);
    }
}

// utilisation
string hello = StringUtil.CapitalizeFirstLetter("salut"); // "Salut"
Console.WriteLine(hello); 

Le code est classique, mais C# te permet de l’écrire beaucoup plus compact.

La ligne

string hello = StringUtil.CapitalizeFirstLetter("salut"); // "Salut"

peut s’écrire comme ça :

string hello = "salut".CapitalizeFirstLetter(); // "Salut"

Et maintenant je t’explique comment ça marche.

2. Comment fonctionnent les Extension Methods

Même si les Extension Methods ont l’air magiques, en vrai c’est assez simple. Une extension method, c’est juste une méthode statique normale, déclarée dans une classe statique, mais avec une différence importante : son premier paramètre est précédé du mot-clé this. C’est ce paramètre qui indique à quel type la méthode « s’applique » comme extension.

Regarde un exemple d’extension du type string :

namespace MyProject.Extensions
{
    // 1. Les Extension Methods doivent être déclarées dans une classe statique.
    public static class StringExtensions
    {
        // 2. La méthode doit être statique.
        // 3. Le premier paramètre doit être précédé de 'this'.
        public static string CapitalizeFirstLetter(this string str)
        {
            if (string.IsNullOrEmpty(str)) 
                return str; 

            // On utilise String.ToUpper et String.Substring pour créer une nouvelle string
            return char.ToUpper(str[0]) + str.Substring(1);
        }

        // Un autre exemple :
        public static int WordCount(this string text)
        {
            if (string.IsNullOrEmpty(text))
                return 0;

            // Compte basique des mots, en découpant sur les espaces
            return text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}    

Pour utiliser ces méthodes, il suffit d’importer le namespace MyProject.Extensions dans ton fichier :

using MyProject.Extensions; // Important : importer le namespace où sont déclarées les Extension Methods

string hello = "salut, monde !";
Console.WriteLine(hello.CapitalizeFirstLetter()); // Affichera : "Salut, monde !"

string sentence = "Ceci est une chaîne de test pour compter les mots.";
Console.WriteLine($"Nombre de mots : {sentence.WordCount()}"); // Affichera : "Nombre de mots : 8"

string emptyString = "";
Console.WriteLine(emptyString.CapitalizeFirstLetter()); // Affichera : ""

Important : Si le mot-clé this n’était pas devant le premier paramètre string str, CapitalizeFirstLetter serait juste une méthode statique normale de la classe StringExtensions, et tu devrais l’appeler comme StringExtensions.CapitalizeFirstLetter("salut"). C’est this qui la transforme en Extension Method, et te permet de l’appeler à la mode objet.

3. Syntaxe des Extension Methods

Pour créer et utiliser des Extension Methods, suis ces étapes :

  1. Crée une classe statique : Toutes les Extension Methods doivent être dans une classe statique. Le nom peut être ce que tu veux, mais en général on l’appelle [TypeName]Extensions (genre StringExtensions, ListExtensions, DateTimeExtensions).
  2. Déclare une méthode statique : Dans ta classe statique, écris une méthode statique normale.
  3. Ajoute this au premier paramètre : Le plus important — le premier paramètre de ta méthode statique doit être précédé du mot-clé this, suivi du type que tu veux étendre. Ce paramètre représente l’instance de l’objet sur lequel tu appelles l’extension.
  4. Importe le namespace : Dans le fichier où tu veux utiliser l’extension, assure-toi d’importer le namespace (using) où ta classe statique avec les Extension Methods est déclarée. Sinon, le compilateur ne trouvera pas tes extensions.
  5. Utilise comme une méthode normale : Maintenant tu peux appeler ton Extension Method comme si c’était une méthode d’instance sur les objets du type concerné.

4. Comment marche la « magie » en vrai

La « magie » des Extension Methods, c’est grâce au compilateur C#. À l’exécution, les Extension Methods ne font pas partie des méthodes du type. En fait, le compilateur C# transforme l’appel à une Extension Method en un appel statique normal.

Quand tu écris obj.Method(args), où Method est une Extension Method, le compilateur, lors de la compilation, le transforme en ContainingClass.Method(obj, args). Ça se fait de façon transparente pour le dev, ce qui donne l’illusion que la méthode fait partie du type.

Résolution des conflits : Extension Methods vs Méthodes normales

Que se passe-t-il si une classe a déjà une méthode « native » (d’instance) avec le même nom et la même signature que ton Extension Method ?

public class MyClass
{
    public void DoSomething(int value)
    {
        Console.WriteLine($"Méthode native MyClass.DoSomething : {value}");
    }
}

public static class MyClassExtensions
{
    public static void DoSomething(this MyClass instance, int value)
    {
        Console.WriteLine($"Extension Method MyClassExtensions.DoSomething : {value}");
    }
}

// Utilisation :
MyClass obj = new MyClass();
obj.DoSomething(10); // Appelle la méthode native MyClass.DoSomething : 10

Règle de priorité : Si la classe a déjà une méthode d’instance avec le même nom et la même signature (nombre et types de paramètres), c’est toujours la méthode native qui sera appelée, pas l’Extension Method. Les Extension Methods ont une priorité plus basse en cas de conflit de noms.

Limitations des Extension Methods

  • Impossible de surcharger (override) des méthodes existantes : Les Extension Methods ne participent pas au polymorphisme.
  • Impossible d’ajouter de nouveaux champs, propriétés ou événements : Tu peux ajouter seulement des méthodes. Tu ne peux pas t’en servir pour ajouter de l’état à un type existant.
  • Impossible d’étendre des classes statiques : Le premier paramètre this doit toujours être une instance (objet) du type.
  • Impossible d’étendre des champs ou propriétés : Tu peux étendre seulement des types.
  • Pas d’accès aux membres privés ou protégés : Les Extension Methods ne peuvent bosser qu’avec les membres public du type étendu.

Mais tu peux ajouter des Extension Methods à :

  • Des interfaces : C’est super puissant ! Tu peux ajouter une méthode à toutes les classes qui implémentent une interface, sans toucher à l’interface ou à chaque classe. Par exemple, tous les types qui implémentent IEnumerable<T> « reçoivent » les Extension Methods de LINQ.
  • Au type object : Ça permet de créer des Extension Methods accessibles sur n’importe quel objet en C#. Mais fais gaffe à pas polluer l’espace de noms global ou créer des conflits de noms.

5. Exemples concrets et Best Practices

Les Extension Methods, c’est pas juste de la théorie, c’est un outil super utile au quotidien. Voilà quelques scénarios pratiques :

1. Étendre DateTime :

Ajouter des méthodes pratiques pour bosser avec les dates, souvent utilisées dans la logique métier.

using System;

namespace MyProject.TimeHelpers
{
    public static class DateTimeExtensions
    {
        public static bool IsWeekend(this DateTime date)
        {
            return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
        }

        public static bool IsWeekday(this DateTime date)
        {
            return !date.IsWeekend(); // On utilise déjà l’Extension Method existante !
        }

        public static DateTime NextDay(this DateTime date)
        {
            return date.AddDays(1);
        }

        public static DateTime AddBusinessDays(this DateTime date, int days)
        {
            DateTime newDate = date;
            while (days > 0)
            {
                newDate = newDate.NextDay();
                if (newDate.IsWeekday())
                {
                    days--;
                }
            }
            return newDate;
        }
    }
}

Utilisation :

using MyProject.TimeHelpers;

DateTime today = DateTime.Now;
if (today.IsWeekend())
{
    Console.WriteLine("Aujourd’hui c’est le week-end !");
}
else
{
    Console.WriteLine("Aujourd’hui c’est un jour de semaine.");
}

DateTime tomorrow = today.NextDay();
Console.WriteLine($"Demain : {tomorrow.ToShortDateString()}");

DateTime futureDate = today.AddBusinessDays(5);
Console.WriteLine($"Dans 5 jours ouvrés ce sera : {futureDate.ToShortDateString()}");

2. Étendre ton propre type (par exemple, Dog) :

Même si t’as accès au code source de la classe, les Extension Methods sont utiles pour séparer la logique utilitaire ou pour respecter le principe de responsabilité unique (Single Responsibility Principle).

namespace MyProject.Animals
{
    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Breed { get; set; }
    }

    public static class DogExtensions
    {
        public static bool IsPuppy(this Dog dog)
        {
            // Définition arbitraire d’un chiot
            return dog.Age < 2;
        }

        public static string GetAgeCategory(this Dog dog)
        {
            if (dog.Age < 1) return "Chiot";
            if (dog.Age < 7) return "Chien adulte";
            return "Chien âgé";
        }

        public static void Bark(this Dog dog)
        {
            Console.WriteLine($"{dog.Name} dit : Ouaf ! Ouaf !");
        }
    }
}

Utilisation :


using MyProject.Animals;

var sharik = new Dog { Name = "Fido", Age = 1, Breed = "Mongrel" };
if (sharik.IsPuppy())
{
    Console.WriteLine($"{sharik.Name} — c’est encore un chiot !"); // Fido — c’est encore un chiot !
}

Console.WriteLine($"{sharik.Name} dans la catégorie : {sharik.GetAgeCategory()}"); // Fido dans la catégorie : Chiot
sharik.Bark(); // Fido dit : Ouaf ! Ouaf !

var rex = new Dog { Name = "Rex", Age = 5, Breed = "Shepherd" };
Console.WriteLine($"{rex.Name} dans la catégorie : {rex.GetAgeCategory()}"); // Rex dans la catégorie : Chien adulte

Best Practices :

Choisis des noms explicites : Les noms des classes d’extension (StringExtensions, ListExtensions) et des méthodes doivent être clairs et refléter leur fonctionnalité.

Range-les dans des namespaces logiques : Grouper les Extension Methods dans des namespaces qui reflètent leur but, pour éviter de polluer les namespaces globaux.

Utilise-les avec modération : Abuse pas des Extension Methods. Si tu peux modifier la classe directement, c’est peut-être plus propre. Les Extension Methods sont top pour ajouter de la fonctionnalité non intrusive.

Évite les conflits de noms : Pense à la priorité des méthodes natives. Si ton Extension Method a le même nom et la même signature qu’une méthode existante, elle ne sera pas appelée.

Méthode claire : Les Extension Methods doivent faire une tâche précise et simple. Évite de les rendre trop complexes.

Testabilité : Les Extension Methods sont juste des méthodes statiques, donc super faciles à tester.

2
Mission
C# SELF, niveau 18, leçon 2
Bloqué
Création d'une méthode d'extension simple pour une chaîne de caractères
Création d'une méthode d'extension simple pour une chaîne de caractères
2
Mission
C# SELF, niveau 18, leçon 2
Bloqué
Extension pour le type int pour travailler avec les nombres
Extension pour le type int pour travailler avec les nombres
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION