Sumário
Olá Amigos.
Neste tópico estarei falando sobre delegates, sobre sua utilização em eventos, em funções, em ações, em lambda expressions, sobre multicasting e a construção de expressões lambdas e Linq.
Iremos começar da base, para entendermos o que realmente é um delegate e como ele pode nos ser útil. Iremos começar com exemplo simples e rápidos, ao modo que cada artigo vai sendo escrito, iremos nos aprofundando mais neste tópico, até chegarmos ao ponto de escrevermos nossas próprias expressões lambdas.
Índice
Vou apontar o índice para os demais artigos conforme forem sendo escritos
- Eventos
- Func, Action & Predicate
- Expressões Lambda
- Escrevendo minhas Expressões lambdas
- Linq
- MultiCasting
- Chamadas Síncronas
- Chamadas Assíncronas
O que é delegate?
Neste artigo, iremos analisar sobre os diversos aspectos de um delegate, como criá-lo e como instanciá-lo e como utilizar o delegate.
Compreendendo o Delegate
Diferente dos ponteiros programados usando C que são apontamentos direto para um endereço de memória, os delegates em C# são mais seguros e fortemente tipados, mais orientado a objetos, um delegate é um type-safe
![]() |
Type-Safe é a capacidade do C# de garantir que um objeto tem suas características preservadas. Está também ligado à forma de acesso em memória deste objeto.
Exemplo: int i = 10; char *s = (char*)i; print(*(s+10)); Em c# isso não é possível, a não ser que você use a palavra chave “unsafe (inseguro)” int i = 10; char *s >> //isto não será permitido fora de um contexto unsafe (inseguro) |
Um delegate mantem 3 informações importantes:
- O endereço do método para o qual deverá ser chamado
- Os parâmetros, se existirem
- O retorno, se existir
![]() |
Delegates podem apontar para métodos estáticos ou de instância. |
Quando um objeto do tipo delegate é criado ele já vem adaptado para ser chamado de forma síncrona ou assíncrona, isto é muito útil quando iremos programar pensando em multi-tarefas, sem ter que criar um objeto de tarefas (Thread).
Iremos falar sobre este assunto,Multi-Tasking, em outro momento.
Definindo um delegate
A definição do delegate em C# segue esta regra:
modificador de acesso delegate retorno (ou void)nome (parâmetros (opcionais))
public delegate int FacaAlgoERetorne(int x, int y); public delegate void SoFacaAlgo(int x, int y); public delegate void FacaAlgo();
Quando o compilador C# interpretar o nosso objeto delegate, ele automaticamente irá criar uma classe que herda de “System.MulticastDelegate” esta classe terá os métodos que iremos utilizar para executar nosso delegate quando necessário. Iremos nos ater apenas ao método “Invoke()”
![]() |
Chega de papo e mãos à obra |
Mãos à obra
Para reforçar o entendimento, iremos escrever uma calculadora simples, que fará as quatro operações básicas. Abaixo o código completo em C#
using System; namespace CalculadoraDelegate { internal class Program { //======================================================== //Criação do nosso delegate private delegate double Operacao(double x, double y); //======================================================== /* veja que nosso delegate tem: * Modificador de acesso (private) * palavra reservada (delegate) * Tipo de retorno (double) * Parâmetros (x e y) * Isso determina como deverá ser a assinatura do método que será utilizado para o nosso delegate. * Caso o método não tenha esta assinatura o erro "Error CS0123 No overload for 'Nome do Método' matches delegate 'namespace.NomeDoDelegate'" será lançado */ private static void Main(string[] args) { Console.Title = "Calculador delegate (CTRL + C para sair)"; double x = LerNumero(); string operacao = LerOperacao(); double y = LerNumero(); //======================================================== //Criando o ponteiro para o delegate, iniciamos com null, pois não sabemos qual operação iremos realizar. Operacao handler = null; //======================================================== //de acordo com a operação utilizada, iremos istanciar o nosso delegate e executar o método associado switch(operacao) { case "+": handler = new Operacao(Somar); break; case "-": handler = new Operacao(Subtrair); break; case "*": handler = new Operacao(Multiplicar); break; case "/": handler = new Operacao(Dividir); break; default: Console.WriteLine("Operação não implementada."); break; } //Executa o método associado Console.WriteLine($"\r\nO resultado da operação {x:N2}{operacao}{y:N2} é {handler.Invoke(x, y):N2}"); Console.ReadKey(); } #region Métodos de leitura private static string LerOperacao() { string validas = "+-*/"; string result = ""; do { Console.Clear(); Console.WriteLine("Informe a operação desejada:"); Console.WriteLine("(+) para Somar."); Console.WriteLine("(-) para Subtrair."); Console.WriteLine("(/) para Dividir."); Console.WriteLine("(*) para Multiplicar."); result = Console.ReadKey().KeyChar.ToString(); if(!validas.Contains(result)) { Console.WriteLine("\r\nInforme uma operação válida."); result = ""; Console.ReadKey(); } } while(String.IsNullOrWhiteSpace(result)); return result; } private static double LerNumero() { double result = 0; do { Console.Clear(); Console.WriteLine("Informe um número."); string numero = Console.ReadLine(); if(!double.TryParse(numero, out result)) { Console.WriteLine("\r\nInforme um número válido."); Console.ReadKey(); } } while(result == 0); return result; } #endregion Métodos de leitura #region Métodos de operação private static double Somar(double x, double y) { return x + y; } private static double Dividir(double x, double y) { return x / y; } private static double Multiplicar(double x, double y) { return x * y; } private static double Subtrair(double x, double y) { return x - y; } #endregion Métodos de operação } }
Entendendo o código
Como podemos ver, a nossa calculadora utiliza o mesmo delegate nas quatro operações.
private delegate double Operacao(double x, double y);
Conforma a operação é definida o delegate é instanciado passando os parâmetros para o mesmo:
//de acordo com a operação utilizada, iremos istanciar o nosso delegate e executar o método associado switch(operacao) { case "+": handler = new Operacao(Somar); break; case "-": handler = new Operacao(Subtrair); break; case "*": handler = new Operacao(Multiplicar); break; case "/": handler = new Operacao(Dividir); break; default: Console.WriteLine("Operação não implementada."); break; }
E ao final, é invocado e recuperado o resultado da operação.
//Executa o método associado Console.WriteLine($"\r\nO resultado da operação {x:N2}{operacao}{y:N2} é {handler.Invoke(x, y):N2}");
É isso ai pessoal 🙂
Até o próximo
♦ Marcelo