Implémenter des méthodes d’extension pour une classe
En règle générale, il existe deux façons d’ajouter une méthode à un type existant :
- Modifiez le code source de ce type. La modification de la source crée une modification cassante si vous ajoutez également des champs de données privés pour prendre en charge la méthode.
- Définissez la nouvelle méthode dans une classe dérivée. Une méthode ne peut pas être ajoutée de cette façon à l’aide de l’héritage pour d’autres types, tels que des structures et des énumérations. Il ne peut pas être utilisé pour « ajouter » une méthode à une classe scellée.
Les méthodes d’extension vous permettent d’ajouter une méthode à un type existant sans modifier le type lui-même ou implémenter la nouvelle méthode dans un type hérité. La méthode d’extension n’a pas besoin de résider dans le même assembly que le type qu’elle étend. Vous appelez une méthode d’extension comme s’il s’agissait d’un membre défini d’un type.
Méthodes d’extension
Les méthodes d’extension vous permettent d’ajouter des méthodes à des types existants sans créer de nouveau type dérivé, recompiler ou modifier le type d’origine. Les méthodes d’extension sont des méthodes statiques, mais elles sont appelées comme si elles étaient des méthodes d’instance sur le type étendu. Pour le code client écrit en C#, F# et Visual Basic, il n’existe aucune différence apparente entre l’appel d’une méthode d’extension et les méthodes définies dans un type.
Liaison de méthodes d’extension au moment de la compilation
Vous pouvez utiliser des méthodes d’extension pour étendre une classe ou une interface, mais pas pour les remplacer. Une méthode d’extension portant le même nom et la même signature qu’une méthode de classe n’est jamais appelée. Au moment de la compilation, les méthodes d’extension ont toujours une priorité inférieure à celle des méthodes d’instance définies dans le type lui-même. En d’autres termes, si un type a une méthode nommée Process(int i)et que vous disposez d’une méthode d’extension avec la même signature, le compilateur est toujours lié à la méthode d’instance. Lorsque le compilateur rencontre un appel de méthode, il recherche une correspondance dans les méthodes d’instance du type. Si aucune méthode d’instance correspondante n’est trouvée, le compilateur recherche toutes les méthodes d’extension définies pour le type. Le compilateur se lie à la première méthode d’extension qu’il trouve.
L’exemple suivant illustre les règles que le compilateur C# suit pour déterminer s’il faut lier un appel de méthode à une méthode d’instance sur le type ou à une méthode d’extension.
namespace ExtensionMethodDemo.PersonNamespace
{
// Define a simple class with properties and methods
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public void Introduce()
{
Console.WriteLine($"Hi, I'm {FirstName} {LastName}, and I'm {Age} years old.");
}
}
}
namespace ExtensionMethodDemo.PersonExtensionsNamespace
{
using ExtensionMethodDemo.PersonNamespace;
// Define an extension method for the Person class
public static class PersonExtensions
{
public static void DisplayFullName(this Person person)
{
Console.WriteLine($"Full Name: {person.FirstName} {person.LastName}");
}
public static bool IsAdult(this Person person)
{
return person.Age >= 18;
}
public static void Introduce()
{
Console.WriteLine($"Extension - Hi, it's nice to meet you.");
}
// Extension method attempting to override Introduce
public static void Introduce(this Person person, string greeting)
{
Console.WriteLine($"{greeting}, I'm {person.FirstName} {person.LastName}, and I'm {person.Age} years old.");
}
}
}
namespace ExtensionMethodDemo
{
using ExtensionMethodDemo.PersonNamespace;
using ExtensionMethodDemo.PersonExtensionsNamespace;
class Program
{
static void Main(string[] args)
{
// Create instances of the Person class
Person person1 = new Person { FirstName = "FName1", LastName = "LName1", Age = 25 };
Person person2 = new Person { FirstName = "FName2", LastName = "LName2", Age = 16 };
// Use the methods of the Person class
person1.Introduce();
person2.Introduce();
// Use the extension methods
person1.DisplayFullName();
Console.WriteLine($"Is {person1.FirstName} an adult? {person1.IsAdult()}");
person2.DisplayFullName();
Console.WriteLine($"Is {person2.FirstName} an adult? {person2.IsAdult()}");
// Use the extension method that attempts to override Introduce
person1.Introduce("Hello");
person2.Introduce("Greetings");
}
}
}
// Output:
// Hi, I'm FName1 LName1, and I'm 25 years old.
// Hi, I'm FName2 LName2, and I'm 16 years old.
// Full Name: FName1 LName1
// Is FName1 an adult? True
// Full Name: FName2 LName2
// Is FName2 an adult? False
// Hello, I'm FName1 LName1, and I'm 25 years old.
// Greetings, I'm FName2 LName2, and I'm 16 years old.
Dans cet exemple, la classe Person a trois propriétés : FirstName, LastNameet Age. La classe Person a également une méthode d’instance Introduce qui écrit un message dans la console.
La classe PersonExtensions définit les méthodes d’extension pour la classe Person. La classe PersonExtensions contient les méthodes d’extension suivantes :
-
DisplayFullName: écrit le nom complet de la personne dans la console. -
IsAdult: retourne une valeur booléenne indiquant si la personne est adulte. -
Introduce: écrit un message dans la console. Cette méthode a deux surcharges : une sans paramètres et une avec un paramètre de chaîne. -
Introduce(this Person person, string greeting): écrit un message dans la console avec un message d’accueil personnalisé. -
Introduce(): écrit un message par défaut dans la console.
La méthode Main crée deux instances de la classe Person et appelle la méthode Introduce sur chaque instance. La méthode Introduce définie dans la classe Person est exécutée. La méthode Introduce sans paramètres dans la classe PersonExtensions n’est pas appelée, car la classe Person a déjà une méthode d’instance Introduce avec la même signature. Le compilateur suit les règles des méthodes d’extension de liaison au moment de la compilation et donne la priorité à la méthode d’instance définie dans le type lui-même. La méthode Main appelle également les méthodes d’extension DisplayFullName, IsAdultet la méthode Introduce surchargée avec un message d’accueil personnalisé. Les méthodes d’extension sont exécutées comme prévu.
Instructions générales
Les méthodes d’extension constituent une option importante pour créer des fonctionnalités réutilisables dans l’écosystème .NET. Toutefois, la modification du code d’un objet ou la dérivation d’un nouveau type chaque fois qu’il est raisonnable et possible de le faire, est toujours considérée comme préférable. Les méthodes d’extension constituent un excellent choix lorsque la source d’origine n’est pas sous votre contrôle, lorsqu’un objet dérivé est inapproprié ou impossible, ou si la fonctionnalité ne doit pas être exposée au-delà de son étendue applicable.
Lorsque vous utilisez des méthodes d’extension pour étendre un type dont vous n’êtes pas en contrôle, vous courez le risque qu’une modification de l’implémentation du type entraîne l’arrêt de votre méthode d’extension. Si vous implémentez des méthodes d’extension pour un type donné, n’oubliez pas les points suivants :
- Une méthode d’extension n’est pas appelée si elle a la même signature qu’une méthode définie dans le type.
- Les méthodes d’extension sont introduites dans l’étendue au niveau de l’espace de noms. Par exemple, si vous avez plusieurs classes statiques qui contiennent des méthodes d’extension dans un espace de noms unique nommé
Extensions, elles seront toutes introduites dans l’étendue par la directiveusing Extensions;.
Pour une bibliothèque de classes que vous avez implémentée, vous ne devez pas utiliser de méthodes d’extension pour éviter d’incrémenter le numéro de version d’un assembly. Si vous souhaitez ajouter des fonctionnalités significatives à une bibliothèque pour laquelle vous êtes propriétaire du code source, suivez les instructions .NET pour le contrôle de version d’assembly.