Délégués et événements
En C#, les délégués et les événements constituent des mécanismes fondamentaux pour créer des applications flexibles et modulaires. Un délégué est un pointeur de méthode type-safe qui permet de passer des méthodes comme paramètres, de les stocker et de les invoquer dynamiquement, offrant ainsi une grande souplesse dans la conception des systèmes. Les événements reposent sur les délégués et implémentent le modèle éditeur-abonné (Publisher-Subscriber), permettant aux objets de notifier d’autres objets lorsque certaines actions se produisent, tout en maintenant un faible couplage entre les composants.
L’utilisation des délégués et événements est essentielle pour concevoir des notifications personnalisées, des systèmes de plugins, des interactions UI, des journaux d’activité et des tâches planifiées. Grâce aux délégués, les méthodes peuvent être encapsulées et manipulées dynamiquement, tandis que les événements gèrent en toute sécurité la liste des abonnés, permettant à plusieurs objets de réagir à une même notification sans interférence. Dans ce tutoriel, le lecteur apprendra à définir, instancier et invoquer des délégués, à créer et souscrire à des événements, et à appliquer ces mécanismes dans des scénarios concrets avec les principes de la POO, les structures de données et les algorithmes efficaces.
En maîtrisant ces concepts, les développeurs seront capables d’implémenter des patrons comme Observer et Command, de construire des architectures basées sur les événements et d’éviter les problèmes courants tels que les fuites mémoire ou la mauvaise gestion des exceptions.
Exemple de Base
textusing System;
namespace DelegatesAndEventsDemo
{
// Définition du type de délégué
public delegate void NotificationHandler(string message);
// Classe éditeur avec un événement
public class Publisher
{
public event NotificationHandler Notify;
public void SendNotification(string message)
{
// Invocation sécurisée de l'événement
Notify?.Invoke(message);
}
}
// Classe abonné
public class Subscriber
{
private string _name;
public Subscriber(string name)
{
_name = name;
}
public void OnNotificationReceived(string message)
{
Console.WriteLine($"{_name} a reçu le message: {message}");
}
}
class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
Subscriber alice = new Subscriber("Alice");
Subscriber bob = new Subscriber("Bob");
// Souscription à l'événement
publisher.Notify += alice.OnNotificationReceived;
publisher.Notify += bob.OnNotificationReceived;
publisher.SendNotification("Bonjour à tous les abonnés !");
// Désinscription de Bob et envoi d'un deuxième message
publisher.Notify -= bob.OnNotificationReceived;
publisher.SendNotification("Deuxième message");
Console.ReadLine();
}
}
Dans cet exemple, le délégué NotificationHandler
définit la signature des méthodes pouvant être abonnées à l'événement, garantissant la sécurité de type. La classe Publisher
contient l'événement Notify
et utilise l'opérateur conditionnel ?.
pour invoquer l'événement en toute sécurité, uniquement si des abonnés existent.
La classe Subscriber
représente les abonnés avec la méthode OnNotificationReceived
, conforme à la signature du délégué. Dans le programme principal, on crée des instances d’éditeurs et d’abonnés, on souscrit à l'événement, puis on l’invoque avec SendNotification
. La désinscription via -=
permet de retirer un abonné, prévenant ainsi les fuites de mémoire.
Ce code illustre plusieurs concepts avancés : délégués typés, encapsulation des événements, découplage des composants, invocation sécurisée et bonnes pratiques C# pour la maintenance et la modularité. Il répond également aux questions fréquentes des débutants sur la raison d'utiliser des événements plutôt que de simples délégués et sur l’usage de l’opérateur conditionnel pour éviter les exceptions.
Exemple Pratique
textusing System;
using System.Collections.Generic;
namespace DelegatesAndEventsAdvanced
{
// Définition du délégué pour le traitement de données
public delegate void DataProcessedHandler(int result);
// Classe de traitement de données
public class DataProcessor
{
public event DataProcessedHandler DataProcessed;
public void ProcessData(List<int> data)
{
int sum = 0;
foreach (var num in data)
{
if (num < 0)
{
Console.WriteLine("Nombre invalide ignoré : " + num);
continue; // Gestion des erreurs
}
sum += num;
}
// Notification des abonnés
DataProcessed?.Invoke(sum);
}
}
// Classe pour le logging
public class Logger
{
public void LogResult(int result)
{
Console.WriteLine($"Résultat enregistré : {result}");
}
}
// Classe pour les alertes
public class Notifier
{
public void SendAlert(int result)
{
if (result > 50)
Console.WriteLine("Alerte ! Le résultat dépasse le seuil : " + result);
}
}
class Program
{
static void Main(string[] args)
{
DataProcessor processor = new DataProcessor();
Logger logger = new Logger();
Notifier notifier = new Notifier();
// Souscription à l'événement
processor.DataProcessed += logger.LogResult;
processor.DataProcessed += notifier.SendAlert;
List<int> sampleData = new List<int> { 10, 20, 30, -5 };
processor.ProcessData(sampleData);
Console.ReadLine();
}
}
Ce second exemple montre l’application des délégués et événements dans un scénario réel. La classe DataProcessor
calcule la somme d’une liste de nombres tout en gérant les valeurs invalides. L’événement DataProcessed
permet à plusieurs abonnés comme Logger
et Notifier
de réagir au résultat sans que le producteur ne connaisse leur nombre ou leur nature, illustrant le patron Observer.
Chaque abonné a une responsabilité distincte : Logger
enregistre le résultat, tandis que Notifier
déclenche une alerte si la somme dépasse un seuil. Les meilleures pratiques sont respectées : invocation sécurisée de l’événement, principe de responsabilité unique, découplage des composants et gestion d’erreurs efficace. Ce modèle est applicable aux systèmes d’analyse basés sur les événements, frameworks de plugins et notifications asynchrones, offrant une solution maintenable et extensible.
Meilleures pratiques et pièges courants :
En C#, il est recommandé d’utiliser des délégués typés et d’encapsuler les événements pour gérer les abonnements de manière sécurisée. L’invocation conditionnelle permet d’éviter les NullReferenceException. Les abonnements doivent être annulés lorsqu’ils ne sont plus nécessaires pour prévenir les fuites mémoire, surtout avec des objets longue durée de vie.
📊 Tableau de Référence
C# Element/Concept | Description | Usage Example |
---|---|---|
Délégué | Pointeur de méthode typé, invocable dynamiquement | public delegate void MyDelegate(int x); |
Événement | Mécanisme de notification basé sur un délégué | public event MyDelegate MyEvent; |
Souscription | Ajout d’une méthode à la liste des abonnés | myPublisher.MyEvent += mySubscriber.MyMethod; |
Désinscription | Retrait d’une méthode pour éviter les fuites | myPublisher.MyEvent -= mySubscriber.MyMethod; |
Invocation conditionnelle | Appel sécurisé d’un événement | MyEvent?.Invoke(42); |
Délégué anonyme | Définition inline d’un délégué | myPublisher.MyEvent += (x) => Console.WriteLine(x); |
Résumé et prochaines étapes :
Les délégués et événements sont essentiels pour concevoir des applications C# flexibles et modulaires. Les concepts clés incluent la définition de délégués typés, la déclaration et la gestion d’événements, la souscription et la désinscription sécurisée. Ils permettent la mise en œuvre de patrons Observer, de callbacks et de systèmes modulaires basés sur les événements.
Pour aller plus loin, il est conseillé d’explorer les événements avancés, la programmation asynchrone avec async/await, et l’intégration des délégués avec LINQ ou la programmation fonctionnelle. Leur application pratique dans des systèmes de notifications, des frameworks de plugins et des pipelines d’analyse consolide la compréhension. Les ressources utiles incluent la documentation Microsoft, les livres sur les design patterns et les projets open-source. La maîtrise des délégués et événements constitue une étape clé pour passer de la programmation C# de base à la conception d’architectures logicielles robustes et maintenables.
🧠 Testez Vos Connaissances
Test Your Knowledge
Test your understanding of this topic with practical questions.
📝 Instructions
- Lisez chaque question attentivement
- Sélectionnez la meilleure réponse pour chaque question
- Vous pouvez refaire le quiz autant de fois que vous le souhaitez
- Votre progression sera affichée en haut