Programação

...now browsing by tag

 
 

Eventos e Delegates em .NET

Terça-feira, Novembro 24th, 2009

Este artigo tem como objectivo esclarecer o que é um delegate e um evento, bem como exemplificar a implementação e a sua utilização numa aplicação.

Delegates

Um delegate é um tipo de referência utilizado para encapsular um método com uma determinada assinatura.

Exemplo:


public delegate string DevolveStringDelegate();

Esta declaração de um delegate pode encapsular qualquer método que não tenha parâmetros de  entrada e devolva um objecto do tipo String.

 

Em exemplo de utilização de delegates

using System;
using System.Collections.Generic;
using System.Text;

namespace Delegates
{
    public class Program
    {
        //Declaração de um delegate que tem como assinatura 
        //uma variável do tipo String 
        delegate void testeDelegate(string s);

        static void Main(string[] args)
        {
            //texto que vai ser escrito na consola  
            string texto= "estou a ver um delegate a funcionar!";
            //Cria-se uma instância do delegate e no construtor passa-se 
            //como parâmetro o nome do método que se quer utilizar, neste  
            //caso o método é o metodoComAssinaturaString porque contém 
            //a mesma assinatura que o delegate, tem como parâmetro  
            //uma variável do tipo String e devolve void
            testeDelegate t = new testeDelegate(metodoComAssinaturaString);

            //invocação do método que o delegate está a referênciar 
            //caso esse método tenha parâmetros, estes são inseridos 
            //ao utilizar o método invoke do delegate 
            t.Invoke(texto);
        }

        public static void metodoComAssinaturaString(string texto)
        {
            Console.WriteLine(texto);
        }
    }
}

E ao executar o programa…

testeDelegate

 

Eventos

Agora que está esclarecido o que é um delegate e como se implementa, vamos utilizar esse conceito e avançar para a implementação de um evento.

Um evento é uma acção que é despoletada quando uma condição que está  estabelecida se torna verdadeira.

Diagrama_Eventos_e_Delegates

Seguindo o diagrama acima apresentado, vou dar um exemplo de um evento. Temos um calendário, como o google calendar (quem publica os eventos) por exemplo, que permite a inserção de uma reunião, depois configuramos o google calendar para nos enviar um e-mail a avisar da reunião (subscrever o evento), no entanto podemos não ter acesso ao e-mail na hora que está marcada a reunião, assim, configuramos o google calendar para nos enviar uma SMS para além do e-mail (subscrever o evento).

Assim, quando chega a hora da reunião recebemos o aviso por dois canais diferentes, email e SMS, e que contém a mesma informação (EventArgs) no entanto a fonte da informação é a mesma, o google calendar!

Vamos então demonstrar um exemplo prático

using System;
using System.Collections.Generic;
using System.Text;

namespace DelegatesAndEvents
{
    //classe que descreve a informação a ser publicada
    public class ProcessarInformacaoEventArgs : EventArgs
    {
        private int _progresso;

        public int progresso
        {
            get { return _progresso; }
            set { _progresso = value; }
        }

    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace DelegatesAndEvents
{
    //declaração do delegate que tem como parametro a 
    //classe ProcessarInformacaoEventArgs
    //que é onde vai ser guardada a informação que é 
    //enviada quando é disparado o evento
    public delegate void TickHandler(object sender,
        ProcessarInformacaoEventArgs p);

    //classe que publica o evento
    public class ProcessarInformacao
    {
        //declaração do evento que utiliza o 
        //delegate TickHandler
        public event TickHandler tick; 

        //Este método serve apenas de exemplo 
        //de processamento de informação
        public void ProcessarInfo()
        {
            long time = 100000000000;

            TimeSpan t = new TimeSpan(time);

            while (t.Ticks > 0)
            {
                t = t.Subtract(new TimeSpan(1000));
                long aux = time - t.Ticks;
                long res = (aux * 100) / time;

                //sempre que executa um ciclo, vai 
                //ser disparado um evento
                //que vai ser recebido por todas as 
                //classes que o subscreveram
                //e envia a informação processada 
                //por cada ciclo da estrutura
                //de decisão while
                OnTick((int)res);
            }
        }

        protected void OnTick(int p)
        {
            //chama o construtor com parametros da 
            //classe ProcessarInformacaoEventArgs
            //e invoca o evento com a informação que foi recebida
            ProcessarInformacaoEventArgs args = new ProcessarInformacaoEventArgs(p);
            tick(this,args);
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Text;

namespace DelegatesAndEvents
{
    //programa que subscreve o evento da classe ProcessarInformacao
    public class Program
    {
        static void Main(string[] args)
        {
            ProcessarInformacao p = new ProcessarInformacao();

            //Subscreve o evento
            p.tick += new TickHandler(p_tick);

            //Executar o processo que vai disparar o evento
            p.ProcessarInfo();
            Console.Read();
        }

        //Aqui é processada a informação enviada quando o evento é disparado
        static void p_tick(ProcessarInformacaoEventArgs p)
        {
            Console.WriteLine(p.progresso);
            Console.Clear();
        }
    }
}

 

Resultado da aplicação – Apresenta a percentagem de informação já processada.

testeEventos

Pode descarregar todos os projectos de este post aqui.

Demos desenvolvidas em VS2005.

O operador Yield (C#)

Quarta-feira, Outubro 14th, 2009

O operador Yield decerto não dos mais utilizados no C#, no entanto pode em muitas situações simplificar o código produzido. Não é o operador de mais fácil compreensão que a linguagem C# disponibiliza ao programadores, no entanto é um operador extremamente útil em algumas situações.

Ele é utilizado num método para ajudar este a retornar uma instância do tipo IEnumerable ou IEnumerator.

Não pode ser utilizado num método anónimo, não pode também ser utilizado num bloco catch ou num bloco try que tenha mais do que uma cláusula catch.

 

Exemplo Prático com a utilização do operador yield :

using System;
using System.Collections;

namespace TesteYield
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (int numero in Exemplo1(5))
            {
                Console.WriteLine(numero);
            }
        }

        public static IEnumerable Exemplo1(int numero)
        {
            for (int i = 0; i < numero; i++)
            {
                yield return i;
            }

            yield break;
        }
    }
}

 

Exemplo Prático com a recorrendo a uma estrutura de dados:

using System;
using System.Collections;
using System.Collections.Generic;

namespace TesteYield
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (int numero in Exemplo1(5))
            {
                Console.WriteLine(numero);
            }
        }

        public static IEnumerable Exemplo1(int numero)
        {
            var res = new List<int>();

            for (int i = 0; i < numero; i++)
            {
                res.Add(i);
            }

            return res;
        }
    }
}

O resultado do programa será:

exemplo1

Quando é utilizado o yield return, não provoca o fim da execução do método, no caso do exemplo 1, o ciclo “for” vai incrementar a variável “i” e guardar o valor na variável do tipo IEnumerable ou IEnumerator.

Exemplo Prático nº2 – como criar facilmente um IEnumerable ou IEnumerator recorrendo ou yield:

using System;
using System.Collections;
using System.Collections.Generic;

namespace TesteYield
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (int numero in Exemplo2())
            {
                Console.WriteLine(numero);
            }
        }

        public static IEnumerable<int> Exemplo2()
        {
            yield return 0;
            yield return 1;
            yield return 2;
            yield return 3;
            yield return 4;

            yield break;
        }
    }
}

 

O resultado do programa será:

exemplo1