Desenvolvedores.Net - TechBlog

Tag Archives: MultiCasting

Delagates Func, Action e Predicate

0
1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas (1 votos, média: 5,00 de 5)
Loading...
1 de julho de 2016

delegateFuncActionPredicate

Veja o índice completo do tópico “Delegate”

Olá 🙂

Nos artigos anteriores vimos o uso do delegates em eventos, para criar chamadas estilo callback, como invocar métodos e como criar seus delegates.

E continuando nosso assunto sobre delegates, iremos falar sobre três importantes delegates dentro do C#, Func, Action e Predicate.

Func & Action

Nos artigos anteriores criamos uma calculadora usando delegate, aproveitando aquele exemplo, iremos reescrever nossa calculadora usando os delegates Func<> e Action<>.

note-taking A única diferença entre estes dois delegates é o retorno, enquanto no Func<> você é obrigado a informar o tipo de retorno esperado, o Action não retorna nada, é um void.

Os dois delegates possuem ao todo 16 parâmetros de entrada cada um e o Func<> mais um de retorno.
Eu nunca precisei usar mais que 3, se começar a usar muitos parâmetros, reveja seu código.

Chega de papo e mãos à obra

Abaixo o código completo da calculadora usando estes dois delegates.

using System;

namespace FuncEAction
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Title = "Calculadora delegate";
            //Criando o ponteiro para o delegate, iniciamos com null, pois não sabemos qual operação iremos realizar.
            Func<double, double, double> handler = null;
            //Ação que será executada
            Action action = null;

            //while(true) ... Yes ...
            while(true)
            {
                string operacao = LerOperacao();

                //de acordo com a operação utilizada, iremos istanciar o nosso delegate e executar o método associado
                switch(operacao)
                {
                    case "+":
                        handler = Somar;
                        break;
                    case "-":
                        handler = Subtrair;
                        break;
                    case "*":
                        handler = Multiplicar;
                        break;
                    case "/":
                        handler = Dividir;
                        break;
                    case "s":
                        action = Exit;
                        break;
                    case "c":
                        action = Clear;
                        break;
                    default:
                        Console.WriteLine("Operação não implementada.");
                        continue;
                }

                if(action != null)
                {
                    //invocar a ação do mal
                    action();
                    action = null;
                    continue;
                }

                double x = LerNumero("primeiro");
                double y = LerNumero("segundo");

                //Executa o método associado
                Console.WriteLine($"\r\nO resultado da operação {x:N2} {operacao} {y:N2} é {handler(x, y):N2}");

                Console.ReadKey();
            }
        }

        #region Métodos de leitura

        private static string LerOperacao()
        {
            string validas = "+-*/cs";
            string result = "";

            do
            {
                DrawMenu();
                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(string text)
        {
            double result = 0;

            do
            {
                Console.Clear();
                Console.WriteLine($"Informe o {text} número da operação.");
                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

        #region Métodos de ação

        private static void Exit()
        {
            Environment.Exit(0);
        }

        private static void Clear()
        {
            Console.Clear();
        }

        private static void DrawMenu()
        {
            Console.WriteLine("Informe a operação desejada:");
            Console.WriteLine("(+) para Somar.");
            Console.WriteLine("(-) para Subtrair.");
            Console.WriteLine("(/) para Dividir.");
            Console.WriteLine("(*) para Multiplicar.");
            Console.WriteLine("(c) para Limpar o log.");
            Console.WriteLine("(s) para Sair.");
        }

        #endregion Métodos de ação
    }
}

Predicate

O tipo Predicate é um delegate especial que possui apenas um parâmetro de entrada e retorna um booleano.
Deve ser utilizado quando precisamos informar uma condição para que a ação seja executada. O nosso predicado, pode executar quantas situações forem necessárias para satisfazer a condição.

No código abaixo, iremos ver um exemplo de uso do Predicate e do Action por classes do C#.

Repare que iremos usar a classe “Array

    internal class Program
    {
        private static void Main(string[] args)
        {
            //Array com o nome dos países
            string[] countries ={
                    "Afeganistão","África do Sul","Akrotiri","Albânia","Alemanha","Andorra","Angola","Anguila","Antártida","Antígua e Barbuda","Antilhas","Arábia Saudita","Arctic Ocean","Argélia","Argentina","Arménia","Aruba","Ashmore andCartier Islands","Atlantic Ocean","Austrália","Áustria","Azerbaijão","Baamas","Bangladeche","Barbados","Barém","Bélgica","Belize","Benim","Bermudas","Bielorrússia","Birmânia","Bolívia","Bósnia e Herzegovina","Botsuana","Brasil","Brunei","Bulgária","Burquina Faso","Burúndi","Butão","Cabo Verde","Camarões","Camboja","Canadá","Catar","Cazaquistão","Chade","Chile","China","Chipre","ClippertonIsland","Colômbia","Comores","Congo-Brazzaville","Congo-Kinshasa","Coral Sea Islands","Coreia do Norte","Coreia doSul","Costa do Marfim","Costa Rica","Croácia","Cuba","Dhekelia","Dinamarca","Domínica","Egipto","EmiratosÁrabes Unidos","Equador","Eritreia","Eslováquia","Eslovénia","Espanha","Estados Unidos","Estónia","Etiópia","Faroé","Fiji","Filipinas","Finlândia","França","Gabão","Gâmbia","Gana","GazaStrip","Geórgia","Geórgia do Sul e Sandwich do Sul","Gibraltar","Granada","Grécia","Gronelândia","Guame","Guatemala","Guernsey","Guiana","Guiné","Guiné Equatorial","Guiné-Bissau","Haiti","Honduras","Hong Kong","Hungria","Iêmen","Ilha Bouvet","Ilha do Natal","Ilha Norfolk","Ilhas Caimão","Ilhas Cook","Ilhas dos Cocos","Ilhas Falkland","Ilhas Heard e McDonald","Ilhas Marshall","Ilhas Salomão","Ilhas Turcas e Caicos","Ilhas Virgens Americanas","Ilhas VirgensBritânicas","Índia","Indian Ocean","Indonésia","Irão","Iraque","Irlanda","Islândia","Israel","Itália","Jamaica","Jan Mayen","Japão","Jersey","Jibuti","Jordânia","Kuwait","Laos","Lesoto","Letónia","Líbano","Libéria","Líbia","Listenstaine","Lituânia","Luxemburgo","Macau","Macedónia","Madagáscar","Malásia","Malávi","Maldivas","Mali","Malta","Man, Isle of","Marianas do Norte","Marrocos","Maurícia","Mauritânia","Mayotte","México","Micronésia","Moçambique","Moldávia","Mónaco","Mongólia","Monserrate","Montenegro","Mundo","Namíbia","Nauru","Navassa Island","Nepal","Nicarágua","Níger","Nigéria","Niue","Noruega","Nova Caledónia","Nova Zelândia","Omã","Pacific Ocean","Países Baixos","Palau","Panamá","Papua-Nova Guiné","Paquistão","Paracel Islands","Paraguai","Peru","Pitcairn","Polinésia Francesa","Polónia","Porto Rico","Portugal","Quénia","Quirguizistão","Quiribáti","Reino Unido","República Centro-Africana","República Checa","República Dominicana","Roménia","Ruanda","Rússia","Salvador","Samoa","Samoa Americana","Santa Helena","Santa Lúcia","São Cristóvão e Neves","São Marinho","São Pedro e Miquelon","São Tomé e Príncipe","São Vicente e Granadinas","Sara Ocidental","Seicheles","Senegal","Serra Leoa","Sérvia","Singapura","Síria","Somália","Southern Ocean","Spratly Islands","Sri Lanca","Suazilândia","Sudão","Suécia","Suíça","Suriname","Svalbard e Jan Mayen","Tailândia","Taiwan","Tajiquistão","Tanzânia","Território Britânico do Oceano Índico","Territórios Austrais Franceses","Timor Leste","Togo","Tokelau","Tonga","Trindade e Tobago","Tunísia","Turquemenistão","Turquia","Tuvalu","Ucrânia","Uganda","União Europeia","Uruguai","Usbequistão","Vanuatu","Vaticano","Venezuela","Vietname","Wake Island","Wallis e Futuna","West Bank","Zâmbia","Zimbabué"
                };

            //imprimir array
            Console.WriteLine("\r\nImprimindo países\r\n");
            Action<string> printArray = (item) => { Console.WriteLine(item); };
            Array.ForEach(countries, printArray);

            //encontrar um último da letra M
            Console.WriteLine("\r\nÚltimo com a letra M\r\n");
            Predicate<string> findLastM = (item) =>
            {
                return item.StartsWith("M", StringComparison.InvariantCultureIgnoreCase);
            };
            Console.WriteLine($"O último com a letra M é {Array.FindLast(countries, findLastM)}");

            //imprimir todos que tem a letra k
            Console.WriteLine("\r\nTodos que tem a letra K\r\n");
            Predicate<string> hasK = (item) =>
            {
                return item.Contains("k");
            };

            string[] ks = Array.FindAll(countries, hasK);
            Array.ForEach(ks, printArray);

            Console.ReadKey();
        }
    }
question Lindo isso, mas eu realmente vou usar?

Sim, vai. Aguarde novidades nos próximos capítulos, quando entrarmos no assunto expressões lambda.

 


É isso ai pessoal 🙂
Até o próximo
♦ Marcelo

About 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

Delegates e Eventos

0
1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas (1 votos, média: 5,00 de 5)
Loading...
28 de junho de 2016

delegateAndEvents

Olá galera. 🙂

Veja o índice completo do tópico “Delegate”

Continuando nossa série sobre delegates, desta vez iremos falar sobre eventos, e quase impossível não entrar no assunto quando estamos falando de delegates.
Neste artigo iremos aprender a escrever os eventos de forma complexa e simples, com o uso da palavra reservada “event“.

note-taking Eventos, de forma geral, é um meio da classe, ou componente enviar mensagens aos seus ouvintes quando algo interessante acontece. Os eventos em C#, utilizam-se de delegates para a troca de mensagens.
Como por exemplo:

  • O Clique do botão;
  • O movimento do cursor;
  • O pressionamento de uma tecla;
  • Uma ação ocorrida;

Entenda eventos como mudanças ou ações que precisam ser notificadas para seus ouvintes, listenners, através de seus objetos, senders.

Além do uso tradicional, iremos ver neste artigo:

  • Eventos em herança;
  • Eventos em interfaces;

Criando eventos

Os eventos em C# são definidos em três passos:

  • Primeiro, criamos o delegate que irá tratar os métodos que serão chamados pelo evento. Opcionalmente podemos usar o delegate “System.EventHandler
  • Segundo, criamos a classe de argumentos para o evento;
  • Terceiro, criamos o evento com o uso da palavra reservada “event“.

Esta declaração segue o padrão de criação de eventos em C#.

Abaixo, iremos ver um exemplo simples da criação de eventos, completo e com o delegate genérico “System.EventHandler“. Preste atenção aos comentários no código.

using System;

//Criando eventos seguindo o padrão de criação definido pelo C#
namespace DelegatesEEventos
{
    //declara o tratador do evento com dois parâmetros
    //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler&amp;lt;&amp;gt;
    //como iremos ver mais abaixo
    public delegate void CustomHandler(object sender, CustomEventArgs args);
    
    //Cria a classe de argumentos do evento
    public class CustomEventArgs: EventArgs
    {
        public string Mensagem { get; private set; }

        public CustomEventArgs(string mensagem)
        {
            Mensagem = mensagem;
        }
    }

    //define uma classe com eventos
    public class ClasseQualquerComEvento
    {
        //Define um evento na classe, usando o nosso delegate
        public event CustomHandler OnFazendoAlgo;

        //Podemos declarar um evento genérico usando o System.EventHandler, 
        //neste caso não é necessário criar o nosso delegate
        public event EventHandler&amp;lt;CustomEventArgs&amp;gt; OnFazendoEventoGenerico;
    }
}

Invocando um evento

Para chamar um evento em C#, basta chamar o mesmo como se fosse um método, passando os parâmetros pedido pelo delegate, seja ele genérico ou não.

   public void FacaAlgo()
        {
            //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar.
            if(OnFazendoAlgo != null)
                //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate
                OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo handler customizado"));

            if(OnFazendoEventoGenerico != null)
                //O mesmo acontece com o delegate genérico
                OnFazendoEventoGenerico(this, new CustomEventArgs("Estou fazendo algo pelo delegate genérico"));
        }

O que acontece por baixo?

UnderTheHood O que acontece por baixo?

Aprendemos a criar o evento usando a palavra reservada “event” para diminuir o tamanho de código digitado. Mas, o que realmente acontece por baixo dos panos?

Quando o compilador encontra a palavra reservada “event“, é criado dois novos métodos pelo C# um “add” e um “remove” seguidos de “_NomeDoEvento“, mas nós também podemos usar esta técnica com as palavras reservadas “add” e “remove“. Veja como ficaria a nossa declaração de eventos no exemplo abaixo:

using System;

//Criando eventos seguindo o padrão de criação definido pelo C#
namespace DelegatesEEventos.AddRemove
{
    //declara o tratador do evento com dois parâmetros
    //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler&lt;&gt;
    //como iremos ver mais abaixo
    public delegate void CustomHandler(object sender, CustomEventArgs args);

    //Cria a classe de argumentos do evento
    public class CustomEventArgs: EventArgs
    {
        public string Mensagem { get; private set; }

        public CustomEventArgs(string mensagem)
        {
            Mensagem = mensagem;
        }
    }

    //define uma classe com eventos
    public class ClasseQualquerComEvento
    {
        //Definimos a instancia do nosso delegate para tratar os eventos
        private CustomHandler customHandler;

        //Define um evento na classe, usando o nosso delegate
        public event CustomHandler OnFazendoAlgo
        {
            add
            {
                lock (customHandler)
                {
                    //adiciona um evento à lista de chamadas
                    customHandler += value;
                }
            }
            remove
            {
                lock (customHandler)
                {
                    //remove um evento da lista de chamadas
                    customHandler -= value;
                }
            }
        }

        public void FacaAlgo()
        {
            //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar.
            if(customHandler != null)
                //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate
                customHandler.Invoke(this, new CustomEventArgs("Olá, estou fazendo algo pelo add/remove"));
        }
    }
}
note-taking Esta abordagem foi apenas para mostrar que podemos criar os métodos de acesso ao evento. Na maioria dos casos a forma tradicional atende.

Eventos em Herança

Vou mostrar duas formas de realizar a chamada de eventos por herança em C#, depois iremos comentar as duas formas e mostrar qual a melhor.

Quando criamos classes, temos que ter em mente que os eventos são um tipo especial de delegates que só podem ser invocados dentro da própria classe, as classes filhas não podem executar estes eventos diretamente.

question Mas como posso fazer com que as minhas classes filhas utilizem os eventos da classe pai?

Para ilustrar a chamada, vamos analisar o código abaixo.

using System;

//Criando eventos seguindo o padrão de criação definido pelo C#
namespace DelegatesEEventos.Heranca
{
    //declara o tratador do evento com dois parâmetros
    //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<>
    //como iremos ver mais abaixo
    public delegate void CustomHandler(object sender, CustomEventArgs args);

    //Cria a classe de argumentos do evento
    public class CustomEventArgs: EventArgs
    {
        public string Mensagem { get; private set; }

        public CustomEventArgs(string mensagem)
        {
            Mensagem = mensagem;
        }
    }

    //define uma classe com eventos
    public class ClasseQualquerComEvento
    {
        //Define um evento na classe, usando o nosso delegate
        //Veja, marcamos como "virtual" o nosso evento
        public virtual event CustomHandler OnFazendoAlgo;

        public void FacaAlgo()
        {
            //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar.
            if(OnFazendoAlgo != null)
                //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate
                OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo método FacaAlgo"));
        }
    }

    //classe herdada
    public class ClasseQualquerComEventoHeranca: ClasseQualquerComEvento
    {
        //Sobrescrevemos o evento que queremos chamar, pois como já foi dito, só podemos 
        //chamar eventos dentro da classe
        public override event CustomHandler OnFazendoAlgo;

        //método qualquer que utiliza o evento
        public void FacaAlgoFilho()
        {
            //Como sobrescrevemos o evento, podemos chamá-lo aqui
            if(OnFazendoAlgo != null)
                OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo pelo método filho"));
        }
    }
}
errado Isto está errado.
A abordagem acima está errada, pois ao chamar o método “FacaAlgo()” da classe pai o evento não será lançado.

ClasseQualquerComEventoHeranca classeQualquerComEventoHeranca = new ClasseQualquerComEventoHeranca();
            classeQualquerComEventoHeranca.OnFazendoAlgo += (s, a) =>
            {
                Console.WriteLine(a.Mensagem);
            };
            classeQualquerComEventoHeranca.FacaAlgo();
            classeQualquerComEventoHeranca.FacaAlgoFilho();
            /* Output:

            Olá, estou fazendo algo pelo método filho

            */

 

note-taking Não marque seus eventos como virtuais, o compilador do C# não irá definir a chamada corretamente, e ao sobrescrever o evento apenas a classe filha atende ao delegate. A ação definida no evento para o  método pai não será invocada.

O padrão correto

Agora, vamos utilizar o padrão correto para este tipo de caso.

  • Crie seu evento como já foi mostrado;
  • Crie um método protegido e virtual para notificar que o evento deverá ocorrer;
using System;

//Criando eventos seguindo o padrão de criação definido pelo C#
namespace DelegatesEEventos.Heranca
{
    //declara o tratador do evento com dois parâmetros
    //Esta declaração pode ser ocultada com o uso do delegate genérico System.EventHandler<>
    //como iremos ver mais abaixo
    public delegate void CustomHandler(object sender, CustomEventArgs args);

    //Cria a classe de argumentos do evento
    public class CustomEventArgs: EventArgs
    {
        public string Mensagem { get; private set; }

        public CustomEventArgs(string mensagem)
        {
            Mensagem = mensagem;
        }
    }

    //define uma classe com eventos
    public class ClasseQualquerComEvento
    {
        //Define um evento na classe, usando o nosso delegate
        //Veja, marcamos como "virtual" o nosso evento
        public event CustomHandler OnFazendoAlgo;

        public void FacaAlgo()
        {
            FazendoAlgoNotify(new CustomEventArgs("Olá, estou fazendo algo pelo método FacaAlgo"));
        }

        //Define o método de notificãção do evento OnFazendoAlgo
        protected virtual void FazendoAlgoNotify(CustomEventArgs args)
        {
            //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar.
            if(OnFazendoAlgo != null)
                //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate
                OnFazendoAlgo(this, args);
        }
    }

    //classe herdada
    public class ClasseQualquerComEventoHeranca: ClasseQualquerComEvento
    {
        //método qualquer que utiliza o evento
        public void FacaAlgoFilho()
        {
            //Como sobrescrevemos o evento, podemos chamá-lo aqui
            FazendoAlgoNotify(new CustomEventArgs("Olá, estou fazendo algo pelo método filho"));
        }

        //se precisar, pode sobrescrever o método
        protected override void FazendoAlgoNotify(CustomEventArgs args)
        {
            //Se necessário. Faça alguma ação antes aqui

            //depois chama o método de base
            base.FazendoAlgoNotify(args);
        }
    }
}
certo Isto está correto.

Como podem ver, ao chamar os dois métodos, o evento será executado duas vezes, pois cada método quer notificar que fez algo.

ClasseQualquerComEventoHeranca classeQualquerComEventoHeranca = new ClasseQualquerComEventoHeranca();
            classeQualquerComEventoHeranca.OnFazendoAlgo += (s, a) =>
            {
                Console.WriteLine(a.Mensagem);
            };
            classeQualquerComEventoHeranca.FacaAlgo();
            classeQualquerComEventoHeranca.FacaAlgoFilho();
            /* Output:

            Olá, estou fazendo algo pelo método FacaAlgo
            Olá, estou fazendo algo pelo método filho

            */

Eventos em interfaces

Interfaces permitem definir a assinatura de seus eventos. Para isso, declare-os normalmente na interface.

Veja o exemplo:

using System;

namespace DelegatesEEventos.Interfaces
{
    //declara o tratador do evento com dois parâmetros
    public delegate void CustomHandler(object sender, CustomEventArgs args);

    //Cria a classe de argumentos do evento
    public class CustomEventArgs: EventArgs
    {
        public string Mensagem { get; private set; }

        public CustomEventArgs(string mensagem)
        {
            Mensagem = mensagem;
        }
    }

    //Define a interface
    public interface IImplementotoEvento
    {
        //Define o evento na interface
        event CustomHandler OnFazendoAlgo;

        //método faça algo
        void FacaAlgo();
    }

    //define uma classe com eventos, e implementa a interface IImplentoEvento
    public class ClasseQualquerComEventoEInterface: IImplementotoEvento
    {
        //Define o evento implementado pela interface
        public event CustomHandler OnFazendoAlgo;

        //define o método implementado na interface
        public void FacaAlgo()
        {
            //Diferente do VB, em C# temos que verificar se o evento não é nulo antes de chamar.
            if(OnFazendoAlgo != null)
                //Basta chamar o evento como se fosse um método da classe, passando os parâmetros definidos no delegate
                OnFazendoAlgo(this, new CustomEventArgs("Olá, estou fazendo algo."));
        }
    }
}

Para chamar, podemos criar uma instância da interface ou a classe diretamente, mas para o exemplo, iremos criar uma instância do tipo da interface.

IImplementotoEvento implentoEvento = new ClasseQualquerComEventoEInterface();
            implentoEvento.OnFazendoAlgo += (s, a) =>
            {
                Console.WriteLine(a.Mensagem);
            };
            implentoEvento.FacaAlgo();

            /* Output:

            Olá, estou fazendo algo.

            */

 


É isso ai pessoal 🙂
Até o próximo
♦ Marcelo

About 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

Delegate

0
1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas (2 votos, média: 5,00 de 5)
Loading...
24 de junho de 2016

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

About 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

Definições – Avançado (POO)

4
1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas (4 votos, média: 4,50 de 5)
Loading...
7 de janeiro de 2011
Para um melhor entendimento deste Artigo veja o Índice (Programação Orientada a Objetos)
Generalização
Generalização é o ato de tornar um objeto geral, agrupar características comuns para objetos dentro de um mesmo contexto, abstrair.
Eu tenho, por hábito e não por regra, a minha classe “Pai de Todas”(superclass) ser sempre abstrata.Veja o diagrama:
Neste caso a minha classe “Pai de Todas”(superclass) é a classe “Pessoa” 

    

Se olharmos de cima para baixo podemos ver todos os objetos gerais, no topo temos a Pessoa, que pode ser um Cliente, um Usuário. O Usuário por sua vez pode ser um Administrador, que tem poderes especiais, o mesmo pode Excluir ou Inserir novos usuários.
E se olharmos de baixo para cima? Aí teremos o próximo tópico Especialização. 🙂

  

Especialização
A especialização nada mais é do que a parte que “especializa” o objeto vindo de uma Generalização, trazer características próprias para o objeto. Seria o mesmo que olhar o diagrama acima de baixo para cima.
Veja:
O objeto Administrador  especializa o objeto Usuario que por sua vez especializa o objeto Pessoa.    

  

Delagates
Os delegates  são ponteiros para funções (métodos).

O que são ponteiros?
Ponteiro é um valor atribuído em memória que aponta para outro valor em memória através de seu endereço. (não gostei, técnico demais pro meu gosto). 
 

 

Quando há a necessidade de usarmos métodos, e ainda não sabemos qual método chamar, pois dependemos de algumas condições, podemos deixar o nosso código mais bonito usando um delegate.   

O delegate irá chamar o método definido de acordo com a nossa necessidade ou condição.   

Veja exemplo:
Abaixo temos um exemplo de uma aplicação Console em C#. 

static class Program
    {
        //declara a assinatura do delegate.
        //os métodos deverão ter a mesma assinatura
        //para que possam ser utilizados pelo delegate
        delegate int Calular(int a, int b);

        static void Main()
        {

            //declara a variável do tipo delegate
            Calular calc;

            //uma condição qualquer
            if (DateTime.Now.Second % 2 == 0)
                //define o método dividir para ser usado no delegate
                calc = new Calular(Dividir);
            else
                //define o método somar para ser usado no delegate
                calc = new Calular(Somar);

            //chama o método
            Console.WriteLine(calc.Invoke(DateTime.Now.Millisecond,
DateTime.Now.Second));

            Console.ReadKey();
        }

        //declara o método somar
        private static int Somar(int a, int b)
        {
            return a + b;
        }

        private static int Dividir(int x, int y)
        {
            return x / y;
        }
    }

Eventos
Eventos são mensagens trocadas pelos sistemas, métodos e objetos para informar um acontecimento, uma ação que se inicia,  que termina dentro da aplicação, como o próprio nome diz, um evento ocorrido.
Vejamos, ao chamar o nosso método Andar() em Pessoa podemos informar que a Pessoa está Andando até que pare de andar , ou podemos informar que a pessoa vai parar de Andar antes de realmente ela parar de Andar. (AntesPararAndar), assim sendo o objeto chamante pode executar alguma ação antes de a Pessoa realmente parar de Andar.  

 Exemplo de eventos em C#:
Para usar eventos em C# temos que fazer uso de delegates como foi visto acima o delegate e um ponteiro para uma função (método), e eventos usam delegates para apontar a qual método o mesmo deverá chamar.   

Declaração de Pessoa

public class Pessoa
    {  
        //declaração da assinatura do delegate
        //que irá tratar os eventos
        public delegate void AndarHandler();

        //este evento irá mostrar que podemos esperar
        //retorno do objeto que chamou
        //o parâmetro pararAndar irá retornar true or false
        //dependendo do caso se for ou não para parar de andar
        public delegate void AndandoHandler(out bool pararAndar);

        //declaração dos eventos
        public event AndarHandler AntesAndar;
        public event AndarHandler AntesPararAndar;

        //repare aqui que iremos usar o segundo delegate
        public event AndandoHandler Andando;
       
        //declaração do método andar
        public void Andar()
        {
            //aqui iremos chamar o evento AntesAndar e avisar
            //o objeto chamante que iremos começar a Andar.
            AntesAndar();

            DateTime pararAs = DateTime.Now.AddSeconds(30);

            //aqui iremos andar por 30 segundos
            while (pararAs > DateTime.Now)
            {
                bool pararAgora = false;
                //aqui iremos notificar que a
                //pessoa continua Andando
                Andando(out pararAgora);

                if (pararAgora)
                {
                    //antes de parar, notificar que vou parar
                    AntesPararAndar();
                    break;
                }

                //aqui apenas iremos parar por um segundo.
                //não se preocupem com esta linha
                System.Threading.Thread.Sleep(1000);
            }
        }
    }

Declaração do objeto para testes.
É uma aplicação do tipo Console. 

static void Main()
        {
            //cria uma pessoa
            Pessoa marcelo = new Pessoa();

            //define os métodos que irão tratar os nossos eventos
            marcelo.Andando +=
new Pessoa.AndandoHandler(marcelo_Andando);
            marcelo.AntesAndar +=
new Pessoa.AndarHandler(marcelo_AntesAndar);
            marcelo.AntesPararAndar +=
new Pessoa.AndarHandler(marcelo_AntesPararAndar);

            //chamar o método para que marcelo possa Andar
            marcelo.Andar();

            Console.WriteLine("Marcelo parou de andar.");

            Console.ReadKey();

        }

        static void marcelo_AntesPararAndar()
        {
            Console.WriteLine("Marcelo irá parar de andar.");
        }

        static void marcelo_AntesAndar()
        {
            Console.WriteLine("Marcelo irá começar a andar.");
        }

        static void marcelo_Andando(out bool pararAndar)
        {
            pararAndar = false;
            //a pessoa marcelo só vai parar se a condição for verdadeira
            if (DateTime.Now.Second % 7 == 0)
                pararAndar = true;

            Console.WriteLine("Marcelo está andando.");
        }
SaberMais Para saber mais sobre delegates.

Foi escrito um novo artigo com tópicos avançados sobre delegates.

Delegates

Com isso terminamos a definição de POO. Aguardem agora os próximos artigos que vamos abordar nesse assunto, ainda temos muita coisa para ver.

Ver Índice

É isso ai pessoal 🙂
Até o próximo
♦ Marcelo

About 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