Event Bus y el patrón Observer en C# (.NET): implementación y ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Event Bus y el patrón Observer en C# (.NET): de la teoría a la práctica



En el desarrollo moderno con C# (.NET), uno de los principios clave es el acoplamiento débil (loose coupling) entre los componentes del sistema. El patrón Observer (Observador) y su evolución — Event Bus (Bus de eventos) — proporcionan un mecanismo elegante para organizar la interacción entre objetos sin dependencias directas. En este artículo, analizaremos en detalle cómo implementar un Event Bus en C# (.NET), examinaremos su arquitectura y presentaremos ejemplos prácticos.



¿Qué es el patrón Observer?

El patrón Observer define una relación de «uno a muchos» entre objetos: cuando un objeto (sujeto) cambia su estado, todos los objetos que dependen de él (observadores) son notificados y actualizados automáticamente. En C#, este patrón se implementa tradicionalmente mediante eventos (event) y delegados.



El problema de la implementación clásica

Aunque los eventos integrados de C# funcionan bien, tienen limitaciones:

  • Conexión directa: el publicador debe conocer explícitamente a los suscriptores.
  • Dificultad para cancelar la suscripción: si un suscriptor olvida cancelar la suscripción, se produce una fuga de memoria.
  • Flexibilidad limitada: es difícil organizar el procesamiento asíncrono o el filtrado de eventos.


¿Qué es un Event Bus?

Un Event Bus es un bus centralizado (mediador) que implementa el patrón Publisher-Subscriber (Publicador-Suscriptor). A diferencia del Observer clásico, el publicador y el suscriptor no se conocen entre sí. Se comunican únicamente a través del bus:

  • Publicador: envía un mensaje (evento) al bus.
  • Bus: encuentra a todos los suscriptores de ese tipo de evento y los notifica.
  • Suscriptor: se registra para un tipo de evento específico y lo procesa.


Ventajas de Event Bus

  • Acoplamiento débil: los componentes no dependen unos de otros.
  • Escalabilidad: es fácil agregar nuevos suscriptores.
  • Capacidad de prueba: se puede sustituir el bus con mocks.
  • Asincronía: se pueden procesar eventos en hilos en segundo plano.


Implementación de Event Bus en C# (.NET)

Consideremos una implementación simple pero funcional. Crearemos una clase EventBus que almacenará un diccionario de suscriptores.



public interface IEventBus{    void Publish<TEvent>(TEvent eventData) where TEvent : class;    IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class;}

public class EventBus : IEventBus{ private readonly Dictionary<Type, List<Delegate>> _subscribers = new(); private readonly object _lock = new();

public void Publish<TEvent>(TEvent eventData) where TEvent : class { List<Delegate> handlers; lock (_lock) { if (!_subscribers.TryGetValue(typeof(TEvent), out var list)) return; handlers = new List<Delegate>(list); }

foreach (var handler in handlers) { if (handler is Action<TEvent> action) action(eventData); } }

public IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class { lock (_lock) { if (!_subscribers.ContainsKey(typeof(TEvent))) _subscribers[typeof(TEvent)] = new List<Delegate>(); _subscribers[typeof(TEvent)].Add(handler); }

return new Unsubscriber(() => { lock (_lock) { if (_subscribers.TryGetValue(typeof(TEvent), out var list)) list.Remove(handler); }

Recommendations