Origem
Quando tratamos do assunto “Delegates”, não podemos esquecer do conceito de Ponteiro de função, vindo lá de trás das linguagens C e C++. Estes conceitos foram muito úteis durante a programação dos Sistemas Operacionais, sendo inteiramente baseada no conceito de funções de retorno de chamada para processar “mensagens”. Exatamente por esta razão foram implementadas mais adiante na linguagem C# os denominados “Delegates”, assumindo este papel necessário no nosso dia a dia. O uso de “Delegates” permite ao programador fazer uma referência a um método, encapsulando a referência do mesmo dentro de um objeto de delegação, adquirindo uma maior flexibilidade para implementar diversas funcionalidades em tempo de execução.
Um pouco mais de teoria
Um “delegate” é um tipo especial de variável definido pelo usuário que é declarada como uma classe. Para métodos estáticos, um objeto “delegate” encapsula o método a ser chamado. Para os métodos de instância, um objeto “delegate” incorpora tanto uma instância e um método na instância. Se você tem um objeto “delegate” e um conjunto apropriado de argumentos, você pode invocar o “delegate” com os argumentos. Na linguagem C# possuímos um código gerenciado, é necessário especificar o tipo de cada parâmetro que um método receberá para que o compilador realize validações nas chamadas de um método. Em outras palavras, podemos dizer que para passar um método por parâmetro este deverá ser um tipo. É neste momento que o .NET Framework oferece os “delegates” como mecanismos que nos permite referenciar os métodos.
Resumo das principais propriedades
1) São como ponteiros de função, mas considerados tipos seguros.
2) Permite que os métodos são passados como parâmetros.
3) Também podem ser usados para definir os métodos de “retorno de chamada“ (callback methods)
4) Podem ser encadeados, como por exemplo, vários métodos podem ser chamados em um único evento.
5) A partir da versão 2.0 do C# foi introduzido o conceito de Métodos anônimos, que permitem que blocos de código a serem passados como parâmetros em vez de um método definido separadamente. Já na versão 3.0 do C #, as expressões lambda foram introduzidas como forma mais concisa de escrever blocos de código embutido. Ambos métodos anônimos e expressões lambda (em determinados contextos) são compilados para delegar tipos. Juntos, esses recursos são agora conhecidos como funções anônimas.
Para entendermos melhor
Antes de entrarmos em detalhes na declaração, sintaxe e uso prático deste mecanismo, vou aprofundar o aprendizado com analogias mais simples. Suponhamos a declaração de uma variável do tipo “string” e como ela se comporta.
Ver Imagem 01.
Figura 01: Alocação de memória de uma variável “string”.
Na Figura 01 podemos ver com detalhes o que acontece quando declaramos uma variável. Declaramos uma variável do tipo “string” e então atribuímos o valor “The Club”, sendo que para esta variável é alocado um endereço de memória que conterá o texto “The Club” e este endereço de memória aponta para a variável de nome “str”.
O funcionamento dos “Delegates” se assemelha com a declaração de uma variável, como por exemplo de um “string”, sendo que a única diferença é que um “delegate” aceita métodos, em outras palavras, podemos dizer que “guarda métodos na memória”. Com esta façanha podemos executá-los no momento que desejarmos, em “run-time”.
Declarando um Delegate
Para declarar um “delegate”, utilizamos a palavra-chave “delegate”. A sintaxe base utilizada para criá-lo é a seguinte:
<Modificador de acesso> delegate <Tipo de Retorno> <Nome do Delegate>([Parametros]);
Exemplo:
public delegate int CalculoQualquer(int valor1, int valor2, int valor3);
Abaixo iremos discorrer de todos os detalhes:
Modificador de Acesso: O modificador pode ser um ou uma combinação adequada dos mesmos, sendo: new, public, private, protected ou internal.
Delegate: Palavra necessária para declarar um “delegate”.
Tipo de Retorno: O tipo de retorno pode ser qualquer tipo de dados (int, string, decimal, etc ...) ou podemos também não retornar nada (void). Os tipos específico como classes, structs também são aceitos.
Nome do Delegate: O nome deve ser um nome válido para um método.
Parâmetros: Valores opcionais, devendo ou não tê-los em sua assinatura, dependendo da necessidade.
Após a declaração de um “delegate”, devemos nos lembrar que o mesmo apenas fornece um modelo para um método, não um método real. Para usá-lo devemos definir um método que levaria uma atribuição do mesmo.
Importante salientar que este método deve ter o mesmo tipo de retorno, número de parâmetros caso exista. Após a implementação do método deveremos associá-lo ao nome do “delegate”.
Exemplo:
CalculoQualquer Calculo = new CalculoQualquer(EfetuarCalculo);
Lembrando que o Método “EfetuarCalculo” deverá possuir a mesma estrutura do “Delegate”, ou seja, três parâmetros de entrada e um de saída ambos inteiros. Veremos mais detalhes adiante.
Criando um Exemplo
Para fixarmos melhor este conceito iremos implementar dois exemplos, sendo o primeiro mais simples e o segundo um pouco mais elaborado. Para isto crie uma aplicação do início no Microsoft Visual Studio clicando em “File/New/Project...” e escolhendo “Windows Forms Application”. Fique a vontade para definir o nome que desejar para o Formulário. O nosso primeiro exemplo irá utilizar apenas um “Button”.
Exemplo 01
A intenção deste exemplo é de mostrar uma mensagem utilizando “Delegates”, Ver Listagem 01.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
Para aplicações Windows Forms usaremos algumas bibliotecas padrões.
...
public delegate void MostrarMensagem();
Declaramos o “delegate”, conforme explicado anteriormente, com o modificador de acesso do tipo “public” e sem nenhum retorno de entrada e de saída.
public MostrarMensagem Mensagem;
Variável pública para atribuir o “delegate” para a mesma.
public void MetodoMensagem()
{
MessageBox.Show("Este é um teste do The Club Trabalhando com 'Delegates'");
}
Método público do tipo “void” (Sem retorno algum), o mesmo tipo de método declarado no “delegate”.
private void button1_Click(object sender, EventArgs e)
{
Mensagem = new MostrarMensagem(MetodoMensagem);
Mensagem();
}
Listagem 01.
Ao clicar no botão faremos a atribuição do método “MetodoMensagem” ao “delegate” (invocando o método em run-time) o chamando da seguinte maneira: “Mensagem()”. Teremos um resultado parecido com a Imagem 02.
Exemplo 02
Para o segundo exemplo iremos criar uma classe chamada “OperacoesMatematicas”. A partir dela criaremos os métodos para as quatro operações matemáticas, possuindo a mesma assinatura de um “delegate” base. Para criar uma classe, clicaremos em “Add/new item/Code” definindo o nome como: “OperacoesMatematicas.cs”. Ver Listagem 02.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BibliotecasTheClub
{
Em “namespace” deixei como padrão de identificação o nome “BibliotecasTheClub”.
public delegate int Operacoes(int value1, int value2);
Teremos a assinatura do “delegate” como modificador de acesso “public”, com retornos de entrada e saída de dados, ambos do tipo “int”.
public class OperacoesMatematicas
{
Dentro da classe implementaremos os métodos “Soma, Subtracao, Multiplicacao e Divisao”.
public int Soma(int valor1, int valor2)
{
return valor1 + valor2;
}
public int Subtracao(int valor1, int valor2)
{
return valor1 - valor2;
}
public int Multiplicacao(int valor1, int valor2)
{
return valor1 * valor2;
}
public int Divisao(int valor1, int valor2)
{
return valor1 / valor2;
}
Teremos todos os métodos com a assinatura exata do delegate.
Listagem 02: Classe “OperacoesMatematicas.cs”.
Para utilizarmos esta classe, voltaremos ao Formulário criado anteriormente e adicionaremos mais um “Button” com os “labels” para resultado da Soma, Subtração, Multiplicação e Divisão dos métodos. Ver Imagem 03.
Figura 03: Exemplo de Formulário.
Podemos conferir a codificação na listagem 03.
public static OperacoesMatematicas ope = new OperacoesMatematicas();
Criaremos a instância da classe a qual contém os métodos que serão atribuídos aos objetos “delegates”.
Operacoes Somar = new Operacoes(ope.Soma);
Operacoes Subtrair = new Operacoes(ope.Subtracao);
Operacoes Multiplicar = new Operacoes(ope.Multiplicacao);
Operacoes Dividir = new Operacoes(ope.Divisao);
Atribuímos os objetos “delegates” denominados “Operacoes” para os métodos “Soma, Subtracao”, Multiplicacao e Divisao”.
private void button2_Click(object sender, EventArgs e)
{
lblSoma.Text = "Soma: " + Somar(4, 2).ToString();
lblSubtracao.Text = "Subtracao: " + Subtrair(4, 2).ToString();
lblMultiplicacao.Text ="Multiplicação: " + Multiplicar(4, 2).ToString();
lblDivisao.Text ="Divisão: " + Dividir(4, 2).ToString();
}
No evento Click do Botão 2 executamos os métodos criados anteriormente, passando sempre dois valores por parâmetro e tendo como retorno um valor inteiro. Sempre respeitando a assinatura base do “delegate”. Ver Imagem 04.

Figura 04: Operações Matemáticas.
Conclusões
Como foi dito ao longo do artigo e expressado através de exemplos práticos, o uso de “delegates” torna-se indispensável para todo programador, possuindo características marcantes como: passar métodos por parâmetros, definição dos métodos de chamada (Callback methods), possibilidade de encadeamento de vários métodos em um único evento, entre outras coisas.
É importante lembrar que a intenção maior deste tutorial foi de desmistificar este importante recurso da linguagem C#, ficando como responsabilidade do desenvolvedor saber quando e onde implementar esta técnica.
Um forte abraço e até o mês que vem!
Nenhum comentário:
Postar um comentário