none
Delegates: Não entendi muito bem. Help! RRS feed

  • Pergunta

  • Olha, sinceramente já olhei na referência da MSDN, no help do VS 2008, no Google e naquele site (http://www.macoratti.net/vbn_dlg.htm) mais ainda assim não entendi qual é realmente a vantagem de se usar um delegate.

    Por exemplo, eu posso declarar uma variável tendo como tipo um delegate e atribuir um método compátivel com a assinatura do delagate (quase igual quando se instância um objeto de uma classe) porém eu realmente não entendi a vantagem de ser fazer isso.

    Não é melhor usar o método diretamente ao invés de fazer várias variáveis que apontam para ele?

    Alguém poderia me explicar isso melhor?

    Muito Obrigado a quem puder ajudar.
    Abraços.
    domingo, 25 de outubro de 2009 12:35

Respostas

  • Olá,

    Em linhas gerais, o delegate serve para você executar um ou mais métodos indiretamente, através do endereço de memória deste(s) método(s). Para quem vem do C/C++, lembra um recurso semelhante chamado "ponteiro para função".

    O principal objetivo, é executar as funções sem que você precise conhecê-las em tempo de compilação.

    Você cria a sua classe X, cria um delegate, e expõe um lugar (variável, evento, etc.) que pode ser usado por quem consome a classe X, para "cadastrar" funções nesse delegate.

    Assim, quando você, dentro da sua classe X executar esse delegate, ele irá disparar todas as funções que foram "cadastradas" lá no seu delegate e você estará executando funções que você nem sabe muito sobre elas... Apenas sabe que elas tem uma assinatura específica, que você definiu no delegate... Mais nada...

    Veja o exemplo abaixo:

    public void ExecutarVariosMetodos()
    {
        Metodo1();
        Metodo2();
        Metodo3();
    }
    

    Esse exemplo mostra um método que faz uma chamada à outros três métodos. Isso não é "apontar". Isso é executar métodos estaticamente, que você conhece em tempo de compilação.

    Agora, imagine uma outra situação. Você precisa criar uma classe que seja capaz de consultar a "previsão do tempo", mas a própria classe não sabe exatamente como fazer isso. Ela apenas fornece a estrutura... Quem for utilizar a classe, terá de fornecer um método/provedor (e é aí que entra o delegate), que será utilizado pela classe para obter a previsão do tempo:

    public class PrevisaoDoTempo
    {
        public int Consultar(string cidade)
        {
            // Existe algum "provedor" de previsão do tempo disponível?
            if (this.Provedor != null)
            {
                // Sim... Então executa o método dinamicamente
                return this.Provedor(cidade);
            }
            else
            {
                throw new InvalidOperationException("Não existe provedor disponível!");
            }
        }
    
        // Essa é a variável que irá armazenar o endereço
        // do(s) método(s) associado(s)
        public ObterDadosPrevisao Provedor;
    }
    
    
    // Essa é a declaração do delegate (criação do tipo)
    public delegate int ObterDadosPrevisao(string cidade);
    


    Na hora de utilizar a classe, você faria algo assim:

    public void btnConsultarPrevisao_Click(object sender, EventArgs e)
    {
        // Cria uma nova instância da sua classe "PrevisaoDoTempo"
        PrevisaoDoTempo p = new PrevisaoDoTempo();
    
        // Adiciona um provedor (o método que vai no Yahoo buscar a previsão)
        p.Provedor += new ObterDadosPrevisao(this.ConsultarPrevisaoYahoo);
    
        // Executa o método Consultar desse objeto da classe PrevisaoDoTempo
        // que indiretamente (em tempo de execução), acaba por executar o método
        // ConsultarPrevisaoYahoo, que você associou via delegate
        int temperatura = p.Consultar("São Paulo");
    }
    
    public int ConsultarPrevisaoYahoo(string cidade)
    {
        // Consulta a previsão do tempo no Yahoo.com,
        // e retorna o valor obtido...
    
        return 12; // Faz de conta que o "12" veio de um WebService :)
    }
    


    No exemplo acima, você pode perceber que a classe PrevisaoDoTempo não conhece exatamente qual método ela irá executar para obter a previsão do tempo... A única coisa que ela sabe, é que esse método recebe uma string com o nome da cidade, e retorna um valor do tipo int, mais nada.

    Se amanhã, você resolver deixar de usar o Yahoo como provedor de previsão do tempo, e passar a utilizar o Google, tudo o que você precisaria fazer, é criar um novo método (com a mesma assinatura), e associá-lo ao delegate.

    ---

    Aproveito para sugerir a leitura dos tópicos abaixo, para ler outras explicações, nas palavras de outros participantes aqui do fórum:

    Para que serverm os Delegates
    http://social.msdn.microsoft.com/Forums/pt-BR/504/thread/44a60855-5ebf-44d4-be3b-389214999072

    Por que usar eventos?
    http://social.msdn.microsoft.com/Forums/pt-BR/504/thread/e5a14450-08c5-4056-b1d4-fc4966308a82

    Abraços,
    Caio Proiete






    Caio Proiete
    Microsoft MVP, MCT, MCPD, MCTS, MCSD
    http://www.caioproiete.com
    • Sugerido como Resposta Ari C. RaimundoModerator domingo, 25 de outubro de 2009 23:39
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:49
    domingo, 25 de outubro de 2009 14:30
    Moderador
  • Shafs,

    O "delegate" pode ser substituido por um método como você falou (Quando em tempo de compilação você conhecer esse método). Porém seu uso será realmente desejado quando você estiver implementando componentes. (Que possam ser reutilizados). 
    Exemplo: Button, TextBox, User controls, ETC. 



    Considere o seguinte cenário: 

    Você precisa implementar algum regra de negócio em seu programa. Essa regra de negócio lhe ajudará a tomar uma decisão e para tomar essa decisão você precisa chamar um método que você não conhece em tempo de codificação. Só o conhecerá em tempo de execução. Ai entra o "delegate" como um ponteiro de Métodos.




    Definição: 
    O que é um delegate? 

    Resposta: O "delegate" é um ponteiro de métodos. Muito usados em eventos. Além da função de ponteiro ele valida se o método preenche os requisitos esperados (Veja exemplo 01).


    Exemplo 01:
    delegate string reviewStatusofARegion(int regionId);
    
    Lendo a declaração do delegate: (obrigatoriamente o método deve retornar uma "string" e deve receber como parâmetro um inteiro) - O meu Delegate validará essas regras e caso a mesmo esteja de acordo ele receberá o ponteiro do "método desconhecido".



      


    Tiago Santos
    Líder do Grupo de Usuários Atitude Brasil.Net (Blog: www.atitudebrasil.net/blogs/tiagosantos)
    MSP, MCP 

    "Atenção:  Se este poste foi útil. Não deixe de marcar como tal."



    Tiago Novaes (MSP, MCP) - tiago.santos@atitudebrasil.net - http://www.atitudebrasil.net - Blog: http://www.atitudebrasil.net/blogs/tiagosantos
    • Sugerido como Resposta Tiago Novaes domingo, 25 de outubro de 2009 17:25
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:48
    domingo, 25 de outubro de 2009 14:11
  • Shafts imagine uma função de ordenação, porém não quer dizer se ela ascendente ou descendente e sim quer que o usuário que irá usar sua função diga isso pra você, o que você faz? Recebe como parâmetro um delegate que irá dizer quando deve substituir um número pelo outro, olhe o exemplo abaixo:

            public delegate bool Comparacao(int valor1, int valor2);
    
            public static void Ordena(int[] array, Comparacao comp)
            {
                for (int i = 0; i < array.Length; i++)
                {
                    for (int j = i + 1; j < array.Length; j++)
                    {
                        if (comp(array[i], array[j]) == true)
                        {
                            int temp = array[i];
                            array[i] = array[j];
                            array[j] = temp;
                        }
                    }
                }
            }
    Bom o que fizemos, um método bubble sort que recebe um array como parâmetro e um delegate da função que irá indicar quando deveremos fazer a troca, essa funcção que é a parte principal do método o usuário poderá escolher (ascendente ou descendente) exemplos:

            public static bool Ascendente(int valor1, int valor2)
            {
                return valor2 < valor1;
            }
    
            public static bool Descendente(int valor1, int valor2)
            {
                return valor2 > valor1;
            }
    
            static void Main(string[] args)
            {
                int[] array = { 5, 8, 2, 0, 1, 4 };
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
    
                Ordena(array, new Comparacao(Ascendente));
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
    
                Ordena(array, new Comparacao(Descendente));
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
            }
    Agora como exemplo também os evento, para declarar um evento no user control você deve ter um delegate para pegar esse evento (handler) e o evento propriamente dito:

    public delegate void MeuEvento(object sender, EventArgs e);
    public event MeuEvento Evento;

    pronto agora toda vez que o usuário gerar o evento ele terá que usar a assinatura acima.

    Resumindo o ponteiro (delegate) para funções serve para que uma função (que não seja a sua naquela momento) possa ser usada dependendo da situação, lógico que se uma função sempre será a mesma você jha deve escrevê-la, porém por exemplo o click de um botão, não se sabe o que o usuário quer fazer com ele, então cria-se um delegate para que o usuário escreve o código dele.
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:48
    domingo, 25 de outubro de 2009 14:29

Todas as Respostas

  • Shafs,

    O "delegate" pode ser substituido por um método como você falou (Quando em tempo de compilação você conhecer esse método). Porém seu uso será realmente desejado quando você estiver implementando componentes. (Que possam ser reutilizados). 
    Exemplo: Button, TextBox, User controls, ETC. 



    Considere o seguinte cenário: 

    Você precisa implementar algum regra de negócio em seu programa. Essa regra de negócio lhe ajudará a tomar uma decisão e para tomar essa decisão você precisa chamar um método que você não conhece em tempo de codificação. Só o conhecerá em tempo de execução. Ai entra o "delegate" como um ponteiro de Métodos.




    Definição: 
    O que é um delegate? 

    Resposta: O "delegate" é um ponteiro de métodos. Muito usados em eventos. Além da função de ponteiro ele valida se o método preenche os requisitos esperados (Veja exemplo 01).


    Exemplo 01:
    delegate string reviewStatusofARegion(int regionId);
    
    Lendo a declaração do delegate: (obrigatoriamente o método deve retornar uma "string" e deve receber como parâmetro um inteiro) - O meu Delegate validará essas regras e caso a mesmo esteja de acordo ele receberá o ponteiro do "método desconhecido".



      


    Tiago Santos
    Líder do Grupo de Usuários Atitude Brasil.Net (Blog: www.atitudebrasil.net/blogs/tiagosantos)
    MSP, MCP 

    "Atenção:  Se este poste foi útil. Não deixe de marcar como tal."



    Tiago Novaes (MSP, MCP) - tiago.santos@atitudebrasil.net - http://www.atitudebrasil.net - Blog: http://www.atitudebrasil.net/blogs/tiagosantos
    • Sugerido como Resposta Tiago Novaes domingo, 25 de outubro de 2009 17:25
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:48
    domingo, 25 de outubro de 2009 14:11
  • Shafts imagine uma função de ordenação, porém não quer dizer se ela ascendente ou descendente e sim quer que o usuário que irá usar sua função diga isso pra você, o que você faz? Recebe como parâmetro um delegate que irá dizer quando deve substituir um número pelo outro, olhe o exemplo abaixo:

            public delegate bool Comparacao(int valor1, int valor2);
    
            public static void Ordena(int[] array, Comparacao comp)
            {
                for (int i = 0; i < array.Length; i++)
                {
                    for (int j = i + 1; j < array.Length; j++)
                    {
                        if (comp(array[i], array[j]) == true)
                        {
                            int temp = array[i];
                            array[i] = array[j];
                            array[j] = temp;
                        }
                    }
                }
            }
    Bom o que fizemos, um método bubble sort que recebe um array como parâmetro e um delegate da função que irá indicar quando deveremos fazer a troca, essa funcção que é a parte principal do método o usuário poderá escolher (ascendente ou descendente) exemplos:

            public static bool Ascendente(int valor1, int valor2)
            {
                return valor2 < valor1;
            }
    
            public static bool Descendente(int valor1, int valor2)
            {
                return valor2 > valor1;
            }
    
            static void Main(string[] args)
            {
                int[] array = { 5, 8, 2, 0, 1, 4 };
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
    
                Ordena(array, new Comparacao(Ascendente));
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
    
                Ordena(array, new Comparacao(Descendente));
    
                foreach (int i in array)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
            }
    Agora como exemplo também os evento, para declarar um evento no user control você deve ter um delegate para pegar esse evento (handler) e o evento propriamente dito:

    public delegate void MeuEvento(object sender, EventArgs e);
    public event MeuEvento Evento;

    pronto agora toda vez que o usuário gerar o evento ele terá que usar a assinatura acima.

    Resumindo o ponteiro (delegate) para funções serve para que uma função (que não seja a sua naquela momento) possa ser usada dependendo da situação, lógico que se uma função sempre será a mesma você jha deve escrevê-la, porém por exemplo o click de um botão, não se sabe o que o usuário quer fazer com ele, então cria-se um delegate para que o usuário escreve o código dele.
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:48
    domingo, 25 de outubro de 2009 14:29
  • Olá,

    Em linhas gerais, o delegate serve para você executar um ou mais métodos indiretamente, através do endereço de memória deste(s) método(s). Para quem vem do C/C++, lembra um recurso semelhante chamado "ponteiro para função".

    O principal objetivo, é executar as funções sem que você precise conhecê-las em tempo de compilação.

    Você cria a sua classe X, cria um delegate, e expõe um lugar (variável, evento, etc.) que pode ser usado por quem consome a classe X, para "cadastrar" funções nesse delegate.

    Assim, quando você, dentro da sua classe X executar esse delegate, ele irá disparar todas as funções que foram "cadastradas" lá no seu delegate e você estará executando funções que você nem sabe muito sobre elas... Apenas sabe que elas tem uma assinatura específica, que você definiu no delegate... Mais nada...

    Veja o exemplo abaixo:

    public void ExecutarVariosMetodos()
    {
        Metodo1();
        Metodo2();
        Metodo3();
    }
    

    Esse exemplo mostra um método que faz uma chamada à outros três métodos. Isso não é "apontar". Isso é executar métodos estaticamente, que você conhece em tempo de compilação.

    Agora, imagine uma outra situação. Você precisa criar uma classe que seja capaz de consultar a "previsão do tempo", mas a própria classe não sabe exatamente como fazer isso. Ela apenas fornece a estrutura... Quem for utilizar a classe, terá de fornecer um método/provedor (e é aí que entra o delegate), que será utilizado pela classe para obter a previsão do tempo:

    public class PrevisaoDoTempo
    {
        public int Consultar(string cidade)
        {
            // Existe algum "provedor" de previsão do tempo disponível?
            if (this.Provedor != null)
            {
                // Sim... Então executa o método dinamicamente
                return this.Provedor(cidade);
            }
            else
            {
                throw new InvalidOperationException("Não existe provedor disponível!");
            }
        }
    
        // Essa é a variável que irá armazenar o endereço
        // do(s) método(s) associado(s)
        public ObterDadosPrevisao Provedor;
    }
    
    
    // Essa é a declaração do delegate (criação do tipo)
    public delegate int ObterDadosPrevisao(string cidade);
    


    Na hora de utilizar a classe, você faria algo assim:

    public void btnConsultarPrevisao_Click(object sender, EventArgs e)
    {
        // Cria uma nova instância da sua classe "PrevisaoDoTempo"
        PrevisaoDoTempo p = new PrevisaoDoTempo();
    
        // Adiciona um provedor (o método que vai no Yahoo buscar a previsão)
        p.Provedor += new ObterDadosPrevisao(this.ConsultarPrevisaoYahoo);
    
        // Executa o método Consultar desse objeto da classe PrevisaoDoTempo
        // que indiretamente (em tempo de execução), acaba por executar o método
        // ConsultarPrevisaoYahoo, que você associou via delegate
        int temperatura = p.Consultar("São Paulo");
    }
    
    public int ConsultarPrevisaoYahoo(string cidade)
    {
        // Consulta a previsão do tempo no Yahoo.com,
        // e retorna o valor obtido...
    
        return 12; // Faz de conta que o "12" veio de um WebService :)
    }
    


    No exemplo acima, você pode perceber que a classe PrevisaoDoTempo não conhece exatamente qual método ela irá executar para obter a previsão do tempo... A única coisa que ela sabe, é que esse método recebe uma string com o nome da cidade, e retorna um valor do tipo int, mais nada.

    Se amanhã, você resolver deixar de usar o Yahoo como provedor de previsão do tempo, e passar a utilizar o Google, tudo o que você precisaria fazer, é criar um novo método (com a mesma assinatura), e associá-lo ao delegate.

    ---

    Aproveito para sugerir a leitura dos tópicos abaixo, para ler outras explicações, nas palavras de outros participantes aqui do fórum:

    Para que serverm os Delegates
    http://social.msdn.microsoft.com/Forums/pt-BR/504/thread/44a60855-5ebf-44d4-be3b-389214999072

    Por que usar eventos?
    http://social.msdn.microsoft.com/Forums/pt-BR/504/thread/e5a14450-08c5-4056-b1d4-fc4966308a82

    Abraços,
    Caio Proiete






    Caio Proiete
    Microsoft MVP, MCT, MCPD, MCTS, MCSD
    http://www.caioproiete.com
    • Sugerido como Resposta Ari C. RaimundoModerator domingo, 25 de outubro de 2009 23:39
    • Marcado como Resposta Shafts domingo, 25 de outubro de 2009 23:49
    domingo, 25 de outubro de 2009 14:30
    Moderador
  • Shafts,

    Após estudar os links dos colegas, dê uma olhada em algo mais profundo abaixo:

    Anonymous Methods (C# Programming Guide)
    http://msdn.microsoft.com/en-us/library/0yw3tz5k.aspx

    Lambda Expressions (C# Programming Guide)
    http://msdn.microsoft.com/en-us/library/bb397687.aspx

    Att.

    Ari C. Raimundo
    • Sugerido como Resposta Tiago Novaes segunda-feira, 26 de outubro de 2009 14:53
    segunda-feira, 26 de outubro de 2009 00:00
    Moderador