Delegates e Eventos
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy. Lição 43 de 70.
Um delegate é um tipo que representa uma referência a um método. Pense nele como uma variável que contém um método em vez de dados. Isso permite passar métodos como argumentos, armazená-los em coleções e chamá-los dinamicamente.
Você declara um delegate especificando a assinatura do método ao qual ele pode fazer referência:
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// Uso
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alerta: Sistema iniciadoEventos baseiam-se em delegados para implementar o padrão publicar-assinar. Uma classe dispara um evento, e outras classes podem se inscrever para receber notificações. A palavra-chave event restringe como o delegado pode ser usado — os assinantes só podem adicionar ou remover manipuladores, não invocar o evento diretamente.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Notifica todos os assinantes
}
}
// Assinando
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Botão foi clicado!O operador += inscreve um manipulador, enquanto -= cancela a inscrição. O padrão ?.Invoke() chama o evento com segurança somente se houver inscritos. Os eventos são fundamentais para aplicações de GUI, mecanismos de jogos e qualquer sistema em que os objetos precisem reagir a mudanças sem um acoplamento rígido.
Desafio
FácilVamos criar um sistema de monitoramento de temperatura que usa delegados e eventos para notificar os assinantes sempre que a temperatura mudar. Este é um exemplo clássico do padrão publicador-assinante que os eventos permitem implementar com muita elegância.
Você organizará seu código em dois arquivos:
TemperatureMonitor.cs: crie uma classeTemperatureMonitorno namespaceMonitoringque atuará como o publicador. Seu monitor deve:- Ter um campo privado para armazenar a temperatura atual
- Declarar um evento usando
Action<int>chamadoTemperatureChanged, que será disparado sempre que a temperatura for atualizada - Ter uma propriedade
Temperature(int), cujo setter atualiza o campo privado e dispara o evento com o novo valor da temperatura
?.Invoke()para disparar o evento com segurança somente quando houver assinantes.Program.cs: no seu arquivo principal, crie umTemperatureMonitore inscreva dois manipuladores diferentes no eventoTemperatureChanged:- Um manipulador que imprime:
Alert: Temperature is now {value} degrees - Outro manipulador que imprime:
Logged: {value}
- Um manipulador que imprime:
Você receberá duas entradas:
- Primeiro valor de temperatura (inteiro)
- Segundo valor de temperatura (inteiro)
Por exemplo, se as entradas forem 25 e 30, a saída deverá ser:
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Observe como definir a propriedade Temperature notifica automaticamente todos os assinantes — o monitor não precisa saber nada sobre quem está ouvindo. Essa é a beleza da abordagem orientada a eventos!
Experimente você mesmo
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Ler entrada
int temp1 = Convert.ToInt32(Console.ReadLine());
int temp2 = Convert.ToInt32(Console.ReadLine());
// TODO: Criar uma instância de TemperatureMonitor
// TODO: Subscribe a handler that prints: "Alert: Temperature is now {value} degrees"
// TODO: Inscrever outro handler que imprime: "Logged: {value}"
// TODO: Definir a temperatura para temp1
// TODO: Definir a temperatura para temp2
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de MétodosPratique por conta própria: Compilador de C# online