Event Bus e o padrão Observer em C# (.NET): implementação e exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Event Bus e o padrão Observer em C# (.NET): da teoria à prática



No desenvolvimento moderno em C# (.NET), um dos princípios-chave é o baixo acoplamento (loose coupling) entre os componentes do sistema. O padrão Observer (Observador) e sua evolução — o Event Bus (Barramento de Eventos) — fornecem um mecanismo elegante para organizar a interação entre objetos sem dependências diretas. Neste artigo, vamos detalhar como implementar um Event Bus em C# (.NET), analisar sua arquitetura e fornecer exemplos práticos.



O que é o padrão Observer?

O padrão Observer define uma relação "um para muitos" entre objetos: quando um objeto (sujeito) altera seu estado, todos os objetos que dependem dele (observadores) são automaticamente notificados e atualizados. Em C#, esse padrão é tradicionalmente implementado por meio de eventos (event) e delegados.



O problema da implementação clássica

Embora os eventos embutidos do C# funcionem bem, eles têm limitações:

  • Conexão direta: o publicador precisa conhecer explicitamente os assinantes.
  • Dificuldade de cancelamento de assinatura: se um assinante esquecer de cancelar a assinatura, ocorre vazamento de memória.
  • Flexibilidade limitada: é difícil organizar processamento assíncrono ou filtragem de eventos.


O que é um Event Bus?

Um Event Bus é um barramento centralizado (mediador) que implementa o padrão Publisher-Subscriber (Publicador-Assinante). Diferentemente do Observer clássico, o publicador e o assinante não se conhecem. Eles se comunicam apenas por meio do barramento:

  • Publicador envia uma mensagem (evento) para o barramento.
  • Barramento encontra todos os assinantes para esse tipo de evento e os notifica.
  • Assinante se registra para um tipo específico de evento e o processa.


Vantagens do Event Bus

  • Baixo acoplamento: os componentes não dependem uns dos outros.
  • Escalabilidade: é fácil adicionar novos assinantes.
  • Testabilidade: é possível substituir o barramento por mocks.
  • Assincronia: é possível processar eventos em threads em segundo plano.


Implementação de um Event Bus em C# (.NET)

Vamos considerar uma implementação simples, mas funcional. Criaremos uma classe EventBus que armazenará um dicionário de assinantes.



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