Pourquoi votre code ne se réveille-t-il que sur appel ?
\nImaginez que vous êtes un répartiteur dans un immense aéroport. Les avions arrivent, les passagers se pressent, les camions de carburant manœuvrent. Si vous deviez personnellement aller voir chaque pilote et demander : « Alors, atterri ? Et maintenant ? Et là ? » — vous deviendriez fou. Au lieu de cela, vous dites : « Quand vous atterrissez — appelez-moi ». Et le système fonctionne parfaitement.
\nC'est ce qu'est l'architecture événementielle en C#. Au lieu d'interroger constamment les objets (pull), nous nous abonnons aux événements (push). Le code devient réactif, évolutif et, surtout, vivant. Dans cet article, nous allons voir comment construire de tels systèmes en C# à partir de zéro, en utilisant les mécanismes intégrés du langage et des modèles avancés.
\n\nQu'est-ce que l'architecture événementielle ? Pas de théorie ennuyeuse
\nL'architecture événementielle est une approche où le flux d'exécution du programme est déterminé par des événements : clics, messages de files d'attente, modifications de données ou signaux externes. En C#, ce concept est intégré directement dans le langage via les délégués (delegates) et les événements (events).
\nLe principe principal est le couplage faible (loose coupling). L'expéditeur de l'événement (éditeur) ne sait rien des destinataires (abonnés). Il se contente de crier : « Quelque chose d'important s'est produit ! » — et qui réagit et comment est décidé dynamiquement.
\nPourquoi est-ce génial pour les projets réels ?
\n- \n
- Évolutivité : Ajouter un nouvel abonné revient à l'inscrire à une newsletter. Le code de l'éditeur ne change pas. \n
- Testabilité : Vous pouvez tester les abonnés de manière isolée, en leur fournissant des événements factices. \n
- Réactivité : Le système réagit lui-même aux changements, sans gaspiller de ressources en sondages inutiles. \n
Mécanisme de base : Délégués et événements en C#
\nAvant de construire l'architecture, comprenons les fondamentaux. En C#, un événement est simplement un délégué spécialisé avec le modificateur event. Un délégué est un type qui stocke une référence à une méthode (ou plusieurs méthodes).
Écrivons notre premier code événementiel
\nImaginez que nous développons un système de maison intelligente. Un capteur de mouvement envoie un signal lorsque quelqu'un entre.
\n\npublic class MotionSensor\n{\n // 1. Déclaration du délégué (type d'événement)\n public delegate void MotionDetectedHandler(object sender, MotionEventArgs e);\n \n // 2. Déclaration de l'événement\n public event MotionDetectedHandler OnMotionDetected;\n\n public void Detect(string location)\n {\n Console.WriteLine($"[Capteur] Mouvement dans {location} !");\n \n // 3. Déclenchement de l'événement (uniquement s'il y a des abonnés)\n OnMotionDetected?.Invoke(this, new MotionEventArgs(location));\n }\n}\n\npublic class MotionEventArgs : EventArgs\n{\n public string Location { get; }\n public DateTime Timestamp { get; } = DateTime.UtcNow;\n\n public MotionEventArgs(string location)\n {\n Location = location;\n }\n}\n\n// Abonné — la lampe\npublic class SmartLight\n{\n public void OnMotion(object sender, MotionEventArgs e)\n {\n if (e.Location == "Salon")\n Console.WriteLine($"[Lampe] J'allume la lumière dans le {e.Location} !");\n else\n Console.WriteLine($"[Lampe] J'ignore {e.Location}.");\n }\n}\n\n// Utilisation\nvar sensor = new MotionSensor();\nvar light = new SmartLight();\n\n// Abonnement de la lampe à l'événement du capteur\nsensor.OnMotionDetected += light.OnMotion;\n\nsensor.Detect("Salon"); // La lampe s'active\nsensor.Detect("Cuisine"); // "J'ignore Cuisine."\n\nImportant : L'utilisation de ?.Invoke est une manière thread-safe de déclencher un événement. Sans la vérification de null, vous risquez une NullReferenceException s'il n'y a pas d'abonnés.
Niveau avancé : EventBus et couplage faible
\nLes abonnements directs sont bien pour