.NET

31 jul, 2013

Desmistificando os Delegates

Publicidade

Olá, pessoal! Ao longo do tempo, é notório a evolução dos frameworks de desenvolvimento em geral, porém a maioria dos desenvolvedores pouco aprende os tópicos que surgem devido ao escasso material claro e que utilize referências ao seu dia a dia. Logo veem suas listas de assuntos a serem estudar aumentando e, o pior de tudo, não utilizam a força máxima que o framework pode disponibilizar nas suas aplicações.

Neste artigo, falarei sobre Delegates e suas aplicações práticas. Para isso, dividirei-o em quatro partes, como segue abaixo:

Desmistificando os Delegates:

  • Parte 1: O que são Delegates e exemplos práticos;
  • Parte 2: Por trás do Common Language Runtime(CLR) e referenciando mais de um método com o MulticastDelegate;
  • Parte 3: Delegates e Eventos;
  • Parte 4: Delegates Actions, Predicate, Funcs, Comparison e Converter.

Vamos lá, então.

O que são Delegates?

Delegates são tipos que referenciam métodos, ou seja, funcionam como ponteiros para outros métodos, mas, diferentemente do C, os Delegates são fortemente tipados. Trocando em miúdos, utilizamos os Delegates para armazenar as referências em outros métodos e, quando o Delegate é executado, automaticamente todos os métodos associados ao Delegate também serão executados.

Quais as vantagens que um Delegate pode nos proporcionar?

  • Delegates permitem que métodos sejam passados por parâmetro, ou seja, a rotina chamará o Delegate sem a necessidade de conhecer os métodos associados a ele em tempo de execução;
  • Como Delegates podem ser passados por parâmetro (conforme item acima), podem ser utilizados como métodos de retorno de chamada. Temos como exemplo em C# o recurso ThreadPool, que possui métodos que recebem como parâmetro Delegates que serão executados em um dado momento (saber mais sobre ThreadPool), chamadas assíncronas, etc;
  • Delegates suportam encadeamento; isso quer dizer que um único Delegate pode fazer referência a vários métodos (contanto que todos os métodos possuam a mesma assinatura e tenham o retorno como void) e todos serão executados na chamada única ao Delegate.

Para criar um Delegate é muito simples, vejamos a assinatura abaixo:

[csharp]

//Declaração do delegate
//<Modificador de acesso> <Tipo de Retorno> delegate <Nome do
Delegate>([Parametros]);
public void delegate ExibirMensagem (String Mensagem);

[/csharp]

Para que a associação entre os métodos e o Delegate funcione, é necessário que os métodos que terão suas referências associadas possuam a mesma assinatura que o Delegate.

Agora, vejamos como é simples atribuir a referência do método ao Delegate:

[csharp]

//Método que será associado ao Delegate
public void MensagemViaConsoleAplication (String Mensagem)
{
Console.WriteLine(Mensagem + " – Mensagem enviada pelo método
MensagemViaConsoleAplication");
}
//Associando o método ao Delegate antes do Framework 2.0
ExibirMensagem testeDelegate = new ExibirMensagem(MensagemViaConsoleAplication);
//Associando o método ao Delegate a partir do Framework 2.0
ExibirMensagem testeDelegate2 = MensagemViaConsoleAplication;
//Associando um método anônimo ao Delegate a partir do Framework 2.0
ExibirMensagem testeDelegate3 = delegate(String Mensagem)
{
Console.WriteLine(Mensagem + " – Mensagem enviada pelo método
MensagemViaConsoleAplication");
};
[/csharp]

E para chamar o Delegate:

[csharp]

//Mensagem “Olá – Mensagem enviada pelo método MensagemViaConsoleAplication”
será exibida no console.
testeDelegate("Olá");

[/csharp]

Estruturando os comandos acima em um projeto do tipo ConsoleApplication, teremos a classe Main abaixo:

[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
//Declaração do Delegate
public delegate void ExibirMensagem(String Mensagem);
static void Main(string[] args)
{
ExibirMensagem(MensagemViaConsoleAplication);
//Associando o método ao Delegate antes do Framework 2.0
ExibirMensagem testeDelegate = new
//Associando o método ao Delegate a partir do Framework 2.0
ExibirMensagem testeDelegate2 = MensagemViaConsoleAplication;
//Associando um método anônimo ao Delegate a partir do Framework 2.0
ExibirMensagem testeDelegate3 = delegate(String Mensagem)
MensagemViaConsoleAplication");
MensagemViaConsoleAplication” será exibida no console.
{
Console.WriteLine(Mensagem + " – Mensagem enviada pelo método
};
//Mensagem “Olá – Mensagem enviada pelo método
testeDelegate("Olá");
testeDelegate2("Olá");
testeDelegate3("Olá");
}
//Método que será associado ao Delegate
public static void MensagemViaConsoleAplication(String Mensagem)
{
MensagemViaConsoleAplication");
}
}
}
Console.WriteLine(Mensagem + " – Mensagem enviada pelo método

[/csharp]

Muito importante!
Como podemos observar no código acima, o Delegate é uma classe, por isso conseguimos declarar variáveis utilizando-o como um tipo e também instanciá-lo.

Mão na massa

Neste momento, você deve estar pensando: “Legal… mas como isso pode me ajudar no dia a dia? Não consigo perceber o que posso fazer com essa funcionalidade!”.

Pensando nisso, vou disponibilizar um exemplo de um pequeno sistema de log. Nele, iremos analisar como utilizar Delegates.

Obs.: Vale salientar que esse pequeno exemplo terá como principal objetivo mostrar estritamente o uso do Delegates em um cenário mais real, por isso não vamos dar ênfase a outros códigos contidos no exemplo, além do mais, os códigos existentes no exemplo estarão mais detalhados para melhor entendimento.

Vamos falar um pouco sobre o projeto.

Ele será um pequeno sistema que o usuário poderá escolher a forma na qual o sistema gerará o log em tempo de execução. Vale salientar que o importante não é a interface gráfica e nem a funcionalidade do projeto por si só, mas sim o que ele poderá agregar num sistema maior.

Não se preocupem, primeiro irei mostrar todo código de que precisaremos e, por fim, explicarei em linhas gerais o que o código faz.

Em primeiro lugar, iremos criar um projeto do tipo Windows Forms Application (você conseguirá aplicar Delegates em outros tipos de projeto como Web etc.). No meu caso, nomeei a solution como “LogSistema – Delegate 1 Parte”.

delegates1.bmp

Altere o formulário padrão criado pelo Visual Studio 2012 (Form1) para Principal – essa alteração foi realizada para melhor organização.

Agora, crie a classe responsável por disponibilizar o serviço de log à nossa interface; no caso deste exemplo, criei com o nome de ServicoLogSistema.cs.

Nossa Soluction Explorer ficará idêntica à imagem abaixo:

delegates2.bmp

Vamos abrir a classe ServicoLogSistema.cs e incluir o código abaixo:

[csharp]

class ServicoLogSistema
{
public delegate void CriarLog(string mensagem);
public static void IniciarGeracaoLog(CriarLog log, string msg)
{
if (log != null)
{
}
}
public static void MensagemViaTxt(string msg)
{
var sw = new StreamWriter("Log.txt", true);
sw.WriteLine(msg);
sw.Close();
}
public static void MensagemViaTela(string msg)
{
}
public static void MensagemSalvaBD(string msg)
{
MessageBox.Show(msg);
//Código para salvar na Base de Dados
}
}

[/csharp]

Agora, iremos abrir o formulário Principal e criar a interface gráfica do nosso pequeno projeto. Nesse caso, vamos criar:

  • 3 checkboxes que irão informar ao sistema de que maneira o usuário deseja armazenar os logs
  • 1 botão que irá ativar a geração do log.

delegates3.bmp

Abra a classe do formulário principal e inclua o código abaixo no método click do botão:

[csharp]

private void btnGerarLog_Click(object sender, EventArgs e)
{
ServicoLogSistema.MensagemViaTela;
ServicoLogSistema.CriarLog log = null;
if (checkBoxLogBD.Checked) log += ServicoLogSistema.MensagemConsole;
if (checkBoxLogMessageBox.Checked) log +=
if (checkBoxLogTxt.Checked) log += ServicoLogSistema.MensagemViaTxt;
ServicoLogSistema.IniciarGeracaoLog(log, "Mensagem Teste");
}

[/csharp]

Trocando o exemplo em miúdos

Como podemos verificar, a classe servicoLogSistema em sua primeira linha declara o delegate chamado CriarLog, recebendo como parâmetro uma variável do tipo string.

Logo depois, temos o método IniciarGeracaoLog que receberá o Delegate e uma variável string como parâmetro, verificará se o mesmo é nulo e executará esse Delegate passando como parâmetro a variável de string.

Logo abaixo, temos três métodos (MensagemViaTxt, MensagemViaTela e MensagemSalvaBD) que serão atribuídos ao Delegate de acordo com a opção escolhida pelo usuário.

Já no formulário Principal, no método click do botão, declaro uma variável do tipo do Delegate. Logo depois, o sistema verifica se o checkbox está marcado e, caso positivo, atribui o método respectivo à variável criada anteriormente (utilizando o operador “+=”; esse conceito é conhecido como MultiCastDelegate, falaremos sobre este assunto mais à frente).

No final, chamamos o método IniciarGeracaoLog passando a variável do tipo Delegate e a mensagem que será utilizada nos métodos associados.

Quando executarmos esse projeto, veremos que a mensagem será exibida da forma que o usuário escolheu nos checkboxes.

Conclusão

Aprendendo Delegates abrimos um leque muito grande de opções, tanto utilizando o Delegate apenas como um simples ponteiro, como utilizando-o como parâmetros para outras funções.

Na próxima parte deste artigo, iremos verificar como o Delegate se comporta dentro da CLR e falaremos um pouco mais sobre MultiCastDelegates.

Baixe aqui o código fonte.