C# - Qual classe Timer devo usar ?


Hoje veremos como decidir qual classe Timer podemos usar em um determinando cenário.

Os temporizadores são usados quando um trecho de código precisa ser executado em um intervalo regular ou depois
uma certa quantidade de tempo.

No entanto, existem mais de uma classe Timer diferentes disponíveis na plataforma .NET. Cada uma delas possui características diferentes e é útil em diferentes cenários.

Você pode encontrar a classe Timer nos seguintes namespaces:

Cabe salientar que a classe Timer não está disponível para todas as implementações e versões da plataforma .NET, como o .NET Standard 1.6 e versões inferiores. Nesses casos, você pode usar a classe System.Threading.Timer.

A mais básica é a classe Timer do namespace System.Threading que pode ser configurada para chamar um único delegate de retorno de chamada após um período especificado. Todos os seus valores de configuração são fornecidos como parâmetros do construtor:

A classe Timer do namespace System.Timers é mais flexível pois ao invés de invocar o CallBack, ela dispara um evento o qual pode ter múltiplos manipuladores, sem que nenhum estado possa ser passado para eles. A sua configuração é feita através das suas propriedades:

        static void Main(string[] args)
        {
            var timer = new Timer(5);
            timer.AutoReset = false;
            timer.Elapsed += (source, eventArgs) =>
            {
                Console.WriteLine("Executando timer");
            };
            timer.Start();
            Console.ReadLine();
        }

- O temporizador é inicialmente desativado e o método Start deve ser chamado para habilitá-lo.
- Podemos parar o temporizador usando o método Stop e reiniciá-lo chamando o método Start novamente.
- Em vez de chamar esses dois métodos, a propriedade Enabled pode ser configurada com o valor apropriado.
- A propriedade AutoReset especifica se o evento Elapsed será invocado apenas uma ou várias vezes.

Os manipuladores de eventos podem ser adicionados ou removidos enquanto o temporizador está em execução e por padrão eles serão chamados em um thread do pool de threads, portanto, o código deve ser seguro para threads, como no caso da classe System.Threading.Timer.

A classe Timer do namespace System.Windows.Forms foi projetada especificamente para ser usada em aplicativos Windows Forms. Os manipuladores de eventos para o seu evento Tick sempre serão invocados na thread da interface do usuário.

Ao seguir as práticas de codificação do Windows Forms, o componente Timer deve ser adicionado a um formulário   usando o designer e as suas propriedades também serão definidas via janela de propriedades do designer sendo que  a interface gráfica do designer vai ocultar o código gerado pelas configurações.

Se você estiver curioso, pode encontrar esse código no arquivo <FormName>.Designer.cs e verá algo parecido com o código a seguir:

this.timer = new System.Windows.Forms.Timer(this.components);
this.timer.Enabled = true;
this.timer.Interval = 50;
this.timer.Tick += new System.EventHandler(this.timer_Tick); 

O código do manipulador de eventos ainda precisará ser gerado  manualmente no arquivo <FormName>.cs. Para isso
bastar dar um duplo clique no componente no designer e isso adicionará um manipulador de eventos vazio :

private void timer_Tick(object sender, EventArgs e)
{
    // seu codigo
}

A interface pública dessa classe Timer é muito semelhante a classe do namespace System.Timers, no entanto, seu evento tem um nome e assinatura diferentes, e não existe a propriedade AutoStart. Isso torna impossível configurar esse timer para ser chamado apenas uma vez. Para conseguir isso, o método Stop deve ser chamado no manipulador de eventos.

Vejamos um exemplo que cria um temporizador de 1 segundo usando o Timer do namespace System.Threading;

using System;
using System.Threading;
namespace CShp_Timers1
{
    class Program
    {
        static public void Tick(Object stateInfo)
        {
            Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
        }
        static void Main(string[] args)
        {
            TimerCallback callback = new TimerCallback(Tick);
            Console.WriteLine("Criando um timer : {0}\n",
                               DateTime.Now.ToString("h:mm:ss"));
            // cria o segundo timer
            Timer stateTimer = new Timer(callback, null, 0, 1000);
            // laço infinito
            for (; ; )
            {
                // adiciona um delay para 100 milisegundos 
                Thread.Sleep(100);
            }
        }
    }
}

Executando teremos:

É para concluir vamos brincar um pouco usando o Timer do namespace System.Timers;

using System;
using System.Timers;
namespace CShp_Timers1
{
    class Program
    {
        static Timer timer = new Timer(1000);
        static int i = 10;
        static void Main(string[] args)
        {
            timer.Elapsed += timer_Elapsed;
            timer.Start(); Console.Read();
        }
        private static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            i--;
            Console.Clear();
            Console.WriteLine("=================================================");
            Console.WriteLine("                  DESARME A BOMBA");
            Console.WriteLine("");
            Console.WriteLine("                Tempo Restante:  " + i.ToString());
            Console.WriteLine("");
            Console.WriteLine("=================================================");
            if (i == 0)
            {
                Console.Clear();
                Console.WriteLine("");
                Console.WriteLine("==============================================");
                Console.WriteLine("         B O O O O O M M M M M ! ! ! !");
                Console.WriteLine("");
                Console.WriteLine("               G A M E  O V E R");
                Console.WriteLine("==============================================");
                timer.Close();
                timer.Dispose();
            }
            GC.Collect();
        }
    }
}

Nota:  O objeto Timer vai ser coletado pelo Garbage Collector assim a referência ao timer deve ser armazenada em uma variável estática para garantir que ele continue em execução.

E estamos conversados.

Pegue o código aqui:  CShp_Timers1.zip

Porque o Filho do homem veio buscar e salvar o que se havia perdido.

Lucas 19:10

"Porque o Filho do homem (Jesus) veio buscar e salvar o que se havia perdido."
Lucas 19:10

Referências:


José Carlos Macoratti