Delegate

Sumário

delegate

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

O que é delegate?

note-taking Podemos dizer que um delegate é uma função de retorno (callback function), um ponteiro para uma função que será chamada em outro momento. Com esta peculiaridade, podemos tratar o clique de um botão, o movimento do mouse, a seleção de um menu. O que chamamos de eventos.
Um delegate suporta chamadas assíncronas, síncronas e multicasting.
Iremos falar disso em outros tópicos

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

note-taking 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:
Em C, podemos declarar algo assim, de forma insegura;
Você declara um inteiro, faz um cast (conversão) para um tipo char e consegue acessar fora dos limites do int.

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
note-taking 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()”

MaosAObra 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

Marcelo

Nascido em Juruaia/MG em uma fazenda de criação de búfalos, e residindo na região Sul do Brasil.
Trabalha com desenvolvimento de aplicações desde os 17 anos. Atualmente é Arquiteto Organizacional na Unimake Software.
Para saber mais ... http://desenvolvedores.net/marcelo
[]'s

Você vai gostar de...

Postagens populares.

Deixe um comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.