Sumário
Olá galera. 🙂
Veja o índice completo do tópico “Delegate”
Continuando nossa série sobre delegates, desta vez iremos falar sobre eventos, e quase impossível não entrar no assunto quando estamos falando de delegates.
Neste artigo iremos aprender a escrever os eventos de forma complexa e simples, com o uso da palavra reservada “event“.
Além do uso tradicional, iremos ver neste artigo:
- Eventos em herança;
- Eventos em interfaces;
Criando eventos
Os eventos em C# são definidos em três passos:
- Primeiro, criamos o delegate que irá tratar os métodos que serão chamados pelo evento. Opcionalmente podemos usar o delegate “System.EventHandler“
- Segundo, criamos a classe de argumentos para o evento;
- Terceiro, criamos o evento com o uso da palavra reservada “event“.
Esta declaração segue o padrão de criação de eventos em C#.
Abaixo, iremos ver um exemplo simples da criação de eventos, completo e com o delegate genérico “System.EventHandler“. Preste atenção aos comentários no código.
using System; //Criando eventos seguindo o padrão de criação definido pelo C# namespace DelegatesEEventos { //declara o tratador do evento com dois parâmetros //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<> //como iremos ver mais abaixo public delegate void CustomHandler(object sender, CustomEventArgs args); //Cria a classe de argumentos do evento public class CustomEventArgs: EventArgs { public string Mensagem { get; private set; } public CustomEventArgs(string mensagem) { Mensagem = mensagem; } } //define uma classe com eventos public class ClasseQualquerComEvento { //Define um evento na classe, usando o nosso delegate public event CustomHandler OnFazendoAlgo; //Podemos declarar um evento genérico usando o System.EventHandler, //neste caso não é necessário criar o nosso delegate public event EventHandler<CustomEventArgs> OnFazendoEventoGenerico; } }
Invocando um evento
Para chamar um evento em C#, basta chamar o mesmo como se fosse um método, passando os parâmetros pedido pelo delegate, seja ele genérico ou não.
public void FacaAlgo() { //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar. if(OnFazendoAlgo != null) //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo handler customizado")); if(OnFazendoEventoGenerico != null) //O mesmo acontece com o delegate genérico OnFazendoEventoGenerico(this, new CustomEventArgs("Estou fazendo algo pelo delegate genérico")); }
O que acontece por baixo?
![]() |
O que acontece por baixo? |
Aprendemos a criar o evento usando a palavra reservada “event” para diminuir o tamanho de código digitado. Mas, o que realmente acontece por baixo dos panos?
Quando o compilador encontra a palavra reservada “event“, é criado dois novos métodos pelo C# um “add” e um “remove” seguidos de “_NomeDoEvento“, mas nós também podemos usar esta técnica com as palavras reservadas “add” e “remove“. Veja como ficaria a nossa declaração de eventos no exemplo abaixo:
using System; //Criando eventos seguindo o padrão de criação definido pelo C# namespace DelegatesEEventos.AddRemove { //declara o tratador do evento com dois parâmetros //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<> //como iremos ver mais abaixo public delegate void CustomHandler(object sender, CustomEventArgs args); //Cria a classe de argumentos do evento public class CustomEventArgs: EventArgs { public string Mensagem { get; private set; } public CustomEventArgs(string mensagem) { Mensagem = mensagem; } } //define uma classe com eventos public class ClasseQualquerComEvento { //Definimos a instancia do nosso delegate para tratar os eventos private CustomHandler customHandler; //Define um evento na classe, usando o nosso delegate public event CustomHandler OnFazendoAlgo { add { lock (customHandler) { //adiciona um evento à lista de chamadas customHandler += value; } } remove { lock (customHandler) { //remove um evento da lista de chamadas customHandler -= value; } } } public void FacaAlgo() { //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar. if(customHandler != null) //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate customHandler.Invoke(this, new CustomEventArgs("Olá, estou fazendo algo pelo add/remove")); } } }
![]() |
Esta abordagem foi apenas para mostrar que podemos criar os métodos de acesso ao evento. Na maioria dos casos a forma tradicional atende. |
Eventos em Herança
Vou mostrar duas formas de realizar a chamada de eventos por herança em C#, depois iremos comentar as duas formas e mostrar qual a melhor.
Quando criamos classes, temos que ter em mente que os eventos são um tipo especial de delegates que só podem ser invocados dentro da própria classe, as classes filhas não podem executar estes eventos diretamente.
![]() |
Mas como posso fazer com que as minhas classes filhas utilizem os eventos da classe pai? |
Para ilustrar a chamada, vamos analisar o código abaixo.
using System; //Criando eventos seguindo o padrão de criação definido pelo C# namespace DelegatesEEventos.Heranca { //declara o tratador do evento com dois parâmetros //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<> //como iremos ver mais abaixo public delegate void CustomHandler(object sender, CustomEventArgs args); //Cria a classe de argumentos do evento public class CustomEventArgs: EventArgs { public string Mensagem { get; private set; } public CustomEventArgs(string mensagem) { Mensagem = mensagem; } } //define uma classe com eventos public class ClasseQualquerComEvento { //Define um evento na classe, usando o nosso delegate //Veja, marcamos como "virtual" o nosso evento public virtual event CustomHandler OnFazendoAlgo; public void FacaAlgo() { //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar. if(OnFazendoAlgo != null) //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo método FacaAlgo")); } } //classe herdada public class ClasseQualquerComEventoHeranca: ClasseQualquerComEvento { //Sobrescrevemos o evento que queremos chamar, pois como já foi dito, só podemos //chamar eventos dentro da classe public override event CustomHandler OnFazendoAlgo; //método qualquer que utiliza o evento public void FacaAlgoFilho() { //Como sobrescrevemos o evento, podemos chamá-lo aqui if(OnFazendoAlgo != null) OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo método filho")); } } }
O padrão correto
Agora, vamos utilizar o padrão correto para este tipo de caso.
- Crie seu evento como já foi mostrado;
- Crie um método protegido e virtual para notificar que o evento deverá ocorrer;
using System; //Criando eventos seguindo o padrão de criação definido pelo C# namespace DelegatesEEventos.Heranca { //declara o tratador do evento com dois parâmetros //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<> //como iremos ver mais abaixo public delegate void CustomHandler(object sender, CustomEventArgs args); //Cria a classe de argumentos do evento public class CustomEventArgs: EventArgs { public string Mensagem { get; private set; } public CustomEventArgs(string mensagem) { Mensagem = mensagem; } } //define uma classe com eventos public class ClasseQualquerComEvento { //Define um evento na classe, usando o nosso delegate //Veja, marcamos como "virtual" o nosso evento public event CustomHandler OnFazendoAlgo; public void FacaAlgo() { FazendoAlgoNotify(new CustomEventArgs("Olá, estou fazendo algo pelo método FacaAlgo")); } //Define o método de notificãção do evento OnFazendoAlgo protected virtual void FazendoAlgoNotify(CustomEventArgs args) { //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar. if(OnFazendoAlgo != null) //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate OnFazendoAlgo(this, args); } } //classe herdada public class ClasseQualquerComEventoHeranca: ClasseQualquerComEvento { //método qualquer que utiliza o evento public void FacaAlgoFilho() { //Como sobrescrevemos o evento, podemos chamá-lo aqui FazendoAlgoNotify(new CustomEventArgs("Olá, estou fazendo algo pelo método filho")); } //se precisar, pode sobrescrever o método protected override void FazendoAlgoNotify(CustomEventArgs args) { //Se necessário. Faça alguma ação antes aqui //depois chama o método de base base.FazendoAlgoNotify(args); } } }
Eventos em interfaces
Interfaces permitem definir a assinatura de seus eventos. Para isso, declare-os normalmente na interface.
Veja o exemplo:
using System; namespace DelegatesEEventos.Interfaces { //declara o tratador do evento com dois parâmetros public delegate void CustomHandler(object sender, CustomEventArgs args); //Cria a classe de argumentos do evento public class CustomEventArgs: EventArgs { public string Mensagem { get; private set; } public CustomEventArgs(string mensagem) { Mensagem = mensagem; } } //Define a interface public interface IImplementotoEvento { //Define o evento na interface event CustomHandler OnFazendoAlgo; //método faça algo void FacaAlgo(); } //define uma classe com eventos, e implementa a interface IImplentoEvento public class ClasseQualquerComEventoEInterface: IImplementotoEvento { //Define o evento implementado pela interface public event CustomHandler OnFazendoAlgo; //define o método implementado na interface public void FacaAlgo() { //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar. if(OnFazendoAlgo != null) //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo.")); } } }
Para chamar, podemos criar uma instância da interface ou a classe diretamente, mas para o exemplo, iremos criar uma instância do tipo da interface.
IImplementotoEvento implentoEvento = new ClasseQualquerComEventoEInterface(); implentoEvento.OnFazendoAlgo += (s, a) => { Console.WriteLine(a.Mensagem); }; implentoEvento.FacaAlgo(); /* Output: Olá, estou fazendo algo. */
É isso ai pessoal 🙂
Até o próximo
♦ Marcelo