views:

184

answers:

4

I want to develop a windows console application which executes an action periodically after a given time. I've read somewhere that a timer class is only available for windows forms applications, so what is the best way to accomplish what I want?

+8  A: 

You can use System.Threading.Timer (or, alternatively, System.Timers.Timer, which is effectively the same as System.Threading.Timer) in a Console application. It's only the Windows Forms or WPF specific timers you want to avoid.

Reed Copsey
A: 

Ok I've figured it out, but how can I invoke my timer so it starts and then make my application sleep forever? This will be always running in background. A simple while(true) at the end is enough? Or maybe Thread.Sleep(Timeout.Infinite)?

zeze
while (true) { } will needlessly consume CPU cycles evaluating whether true == true. Sleeping is far more appropriate as it will suspend the main thread (and not consume CPU cycles).
Michael
+1  A: 

Using Rx you can do this:

        var timer = Observable.Interval(TimeSpan.FromSeconds(1));
        timer.Subscribe(l => Console.WriteLine(l));
        Thread.Sleep(Timeout.Infinite);

Just another option.

Richard Hein
A: 

I wrote this sample console application (using C# 4.0 [as indicated by the default parameters]). It's extremely versatile and utilizes the Action delegate to allow passing snippets that you want executed using the Timer class (in System.Threading). The overloaded Do method of the At static class does all the legwork of computing the interval of delay. You can optionally have the snipped repeated by specifying an interval (in milliseconds). You can of course modify the method to accept TimeSpan for the repeat interval.

Note - the order of when a snippet is to be executed is independent, as the Timer object created will simply queue up the Timer callback on the specific interval, not the order in which the calls to a new Timer object are made.

   using System;
   using System.Threading;

   namespace ConsoleApplication1
   {
  /// <summary>
  /// Class that manages the execution of tasks sometime in the future.
  /// </summary>
  public static class At
  {
     #region Members

     /// <summary>
     /// Specifies the method that will be fired to execute the delayed anonymous method.
     /// </summary>
     private readonly static TimerCallback timer = new TimerCallback(At.ExecuteDelayedAction);

     #endregion

     #region Methods

     /// <summary>
     /// Method that executes an anonymous method after a delay period.
     /// </summary>
     /// <param name="action">The anonymous method that needs to be executed.</param>
     /// <param name="delay">The period of delay to wait before executing.</param>
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param>
     public static void Do(Action action, TimeSpan delay, int interval = Timeout.Infinite)
     {
        // create a new thread timer to execute the method after the delay
        new Timer(timer, action, Convert.ToInt32(delay.TotalMilliseconds), interval);

        return;
     }

     /// <summary>
     /// Method that executes an anonymous method after a delay period.
     /// </summary>
     /// <param name="action">The anonymous method that needs to be executed.</param>
     /// <param name="delay">The period of delay (in milliseconds) to wait before executing.</param>
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param>
     public static void Do(Action action, int delay, int interval = Timeout.Infinite)
     {
        Do(action, TimeSpan.FromMilliseconds(delay), interval);

        return;
     }

     /// <summary>
     /// Method that executes an anonymous method after a delay period.
     /// </summary>
     /// <param name="action">The anonymous method that needs to be executed.</param>
     /// <param name="dueTime">The due time when this method needs to be executed.</param>
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param>
     public static void Do(Action action, DateTime dueTime, int interval = Timeout.Infinite)
     {
        if (dueTime < DateTime.Now)
        {
           throw new ArgumentOutOfRangeException("dueTime", "The specified due time has already elapsed.");
        }

        Do(action, dueTime - DateTime.Now, interval);

        return;
     }

     /// <summary>
     /// Method that executes a delayed action after a specific interval.
     /// </summary>
     /// <param name="o">The Action delegate that is to be executed.</param>
     /// <remarks>This method is invoked on its own thread.</remarks>
     private static void ExecuteDelayedAction(object o)
     {
        // invoke the anonymous method
        (o as Action).Invoke();

        return;
     }

     #endregion
  }

  class Program
  {
     static void Main(string[] args)
     {
        Console.WriteLine("Time: {0} - started", DateTime.Now);

        // demonstrate that order is irrelevant
        At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 5s)", DateTime.Now), DateTime.Now.AddSeconds(5));
        At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 3s)", DateTime.Now), DateTime.Now.AddSeconds(3));
        At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 1s)", DateTime.Now), DateTime.Now.AddSeconds(1));

        At.Do
        (
           () =>
           {
              // demonstrate flexibility of anonymous methods
              for (int i = 0; i < 10; i++)
              {
                 Console.WriteLine("Time: {0} - Hello World! - i == {1} (after 4s)", DateTime.Now, i);
              }
           },
           TimeSpan.FromSeconds(4)
        );

        // block main thread to show execution of background threads
        Thread.Sleep(100000);

        return;
     }
  }
   }
Michael