Pular para o conteúdo
.NETEventos e EventHandler
Módulo 01Fundamentos da Plataforma e da Linguagem

Eventos e EventHandler

intermediario 24 min de leitura·Atualizado · .NET 9
Resumo

Um evento é um delegate com regras de encapsulamento: a classe que o declara pode dispará-lo; quem está fora só pode inscrever-se (+=) ou cancelar (-=). É o padrão publish/subscribe da BCL.

1. Objetivos de Aprendizagem#

  • Declarar e disparar eventos.
  • Inscrever e cancelar assinaturas.
  • Usar a convenção EventHandler/EventArgs.

2. Pré-requisitos#

  • Delegates e lambdas (tópicos 9.1 e 9.2).

3. Conceito#

Um evento é construído sobre um delegate, mas com proteção: só a classe declarante pode invocá-lo. Assinantes usam += para registrar um handler e -= para remover.

A convenção do .NET usa EventHandler<TEventArgs>, cujo handler recebe (object? sender, TEventArgs e). O porquê: desacoplar quem gera o evento de quem reage — o publicador não conhece os assinantes.

Carregando diagrama…

4. Mão na Massa#

4.1. Setup#

Shell
dotnet new console -n Catalog.Eventos
cd Catalog.Eventos

4.2. Implementação Passo a Passo#

  1. Dados do evento e publicador:
C#
public class ProdutoCriadoEventArgs : EventArgs
{
    public string Nome { get; init; } = "";
}

public class Catalogo
{
    public event EventHandler<ProdutoCriadoEventArgs>? ProdutoCriado;

    public void Criar(string nome)
    {
        // ... salva o produto ...
        ProdutoCriado?.Invoke(this, new ProdutoCriadoEventArgs { Nome = nome });
    }
}
  1. Assinantes reagem:
C#
var catalogo = new Catalogo();
catalogo.ProdutoCriado += (sender, e) => Console.WriteLine($"E-mail: '{e.Nome}' criado");
catalogo.ProdutoCriado += (sender, e) => Console.WriteLine($"Cache: invalidando '{e.Nome}'");

catalogo.Criar("Monitor");
// E-mail: 'Monitor' criado
// Cache: invalidando 'Monitor'

4.3. Executando#

Shell
dotnet run

5. Exemplo Completo#

O Catalogo dispara ProdutoCriado sem saber quem escuta; dois assinantes independentes reagem. Esse desacoplamento é a mesma ideia das notifications do MediatR vistas no curso de Web API.

6. Boas Práticas e Armadilhas#

FaçaEvite
Usar ?.Invoke para disparar (evita erro se não há assinantes)Invocar o evento sem checar null
Cancelar assinaturas (-=) quando não precisar maisDeixar assinaturas presas (vazamento de memória)
Seguir a convenção EventHandlerExpor o delegate cru como campo público
Atenção

assinantes que nunca cancelam a assinatura mantêm o publicador "vivo" na memória (memory leak clássico). Em componentes de longa duração, cancele com -=.

7. Segurança e Produção#

  • Handlers que lançam exceção podem interromper o disparo dos demais. Em cenários críticos, isole cada handler (try/catch) ou use um mecanismo de mensageria mais robusto.

8. Exercícios#

  • Fácil: adicione um terceiro assinante ao exemplo.
  • Médio: crie um evento PrecoAlterado com o preço antigo e o novo em EventArgs.
  • Desafio: demonstre um vazamento por assinatura não cancelada e conserte-o.

9. Resumo#

Eventos são delegates encapsulados para publish/subscribe: a classe dispara, assinantes usam +=/-=. Siga a convenção EventHandler<T>, dispare com ?.Invoke e cancele assinaturas para evitar leaks.

10. Próximos Passos#

Encerramos delegates/eventos. A seguir, lidar com falhas: exceções.

11. Referências#

09-03 — Eventos e EventHandler | Curso ASP.NET Core