In this article, we are going to learn how to use Timer in C#. We can set a timer to generate events following a previously set interval. In addition, the Timer class does this without blocking our program’s main execution thread.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

How Does Timer Work in C#?

Let’s see an example of how to use a Timer in C#:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public class Program
{
    public static void Main(string[] args)
    {
        var timer = new Timer(2000);
        timer.Elapsed += OnEventExecution;
        timer.Start();

        Console.ReadLine();
    }

    public static void OnEventExecution(Object? sender, ElapsedEventArgs eventArgs)
    {
        Console.WriteLine($"Elapsed event at {eventArgs.SignalTime:G}");
    }
}

Here, we create an instance of the Timer class. We use the constructor to set up a 2000 milliseconds (2 seconds) interval. After that, we use the OnEventExecution static method as our event handler and we assign it to the timer’s Elapsed event. Finally, we call the Start() method so the events start to fire at the defined interval. Another way to start the timer would be to set the Enabled property to true.

On execution, we should see the program printing a new line to the console every 2 seconds:

Elapsed event at 3/19/2022 12:20:11 PM
Elapsed event at 3/19/2022 12:20:13 PM
Elapsed event at 3/19/2022 12:20:15 PM

In other words, our timer raises the elapsed event repeatedly using the interval we set up initially.

If needed, we can stop a timer by calling its Stop() method or by setting its Enabled property to false.

Generating Recurring Events with Timer in C#

Any newly created timer will repeatedly raise events once started. That’s because the timer’s AutoReset property is set to true by default.

However, in a scenario where we only need our timer to raise the Elapsed event once we should set the AutoReset property to false:

var timer = new Timer(2000);
timer.Elapsed += OnEventExecution;
timer.AutoReset = false;  // Disable recurrent events.
timer.Start();

This time the output consists of one line only because the event was triggered once.

Implementing Handlers

So far, we’ve been using explicitly defined methods as event handlers for our timer. However, we have more options to implement our handlers.

Whenever we deal with really simple handlers, we can use lambda syntax to shorten the implementation:

var timer = new Timer(2000);

timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine($"Elapsed event at {eventArgs.SignalTime:G}");
};

timer.Start();

We can implement asynchronous event handlers as well:

var sw = new StringWriter();
var timer = new Timer(2000);

timer.Elapsed += async (sender, eventArgs) =>
{
    await sw.WriteLineAsync($"Elapsed event at {eventArgs.SignalTime:G}");
};

timer.Start();

Exception Handling

Whenever a timer event handler throws an exception, the timer component catches it and suppresses it. For instance, the following code won’t write any exception messages to the console:

var timer = new Timer(2000);

timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine($"Elapsed event at {eventArgs.SignalTime:G}");
    throw new Exception();
};

timer.Start();

Note that we must never rely on this behavior since it is bound to change in future versions of the .NET Framework.

On the other hand, exceptions raised within asynchronous handlers will not be suppressed by the timer component:

var timer = new Timer(2000);

timer.Elapsed += async (sender, eventArgs) =>
{
    await Task.Run(() => Console.WriteLine($"Elapsed event at {eventArgs.SignalTime:G}"));
    throw new Exception();
};

timer.Start();

This time the program will show the error message and exit.

Disposing Timers

The Timer component implements the IDisposable interface. In most cases, timer instances in our applications will be disposed of automatically when they go out of scope. However, in certain cases, we have to do it manually:

using (var timer = new Timer(2000))
{
    timer.Elapsed += (sender, eventArgs) =>
    {
        Console.WriteLine($"Elapsed event at {eventArgs.SignalTime:G}");
    };

    timer.Start();
    Console.ReadLine();  // Avoids ending the timer's scope too soon
}

We leverage the using statement to dispose of our timer once we are done with it.

Timer and Windows Forms

Usually, Timer calls the Elapsed event handler in the system-thread pool. This may not work when the source of the event is a visual Windows Forms component like a Form, a TextBox, or a Button.

To avoid this pitfall, we must set the SynchronizingObject property to reference the component that handles the event. This way, our Timer will call the event handler in the same thread where the component is located.

Alternatives to Timer in C#

System.Timers and the Timer class have been a part of the framework since version 1.1 so it is available in whichever target framework we work with. However, the framework includes other Timer classes, each one with a different purpose and behavior.

System.Threading.Timer executes a given method a single time after a set interval. The callback method needs to be provided in the constructor and can’t be changed.

System.Windows.Forms.Timer is a Windows Forms component suited for single-thread environments.

System.Web.UI.Timer is part of ASP.NET and performs page postbacks at regular intervals. Only available in .NET Framework.

Timer vs Stopwatch

Timer executes events in a separate thread at a specific user-defined interval. On the other hand, Stopwatch runs in our program’s main thread and measures the elapsed time. Stopwatch returns a TimeSpan struct containing the elapsed time:

var stopwatch = new Stopwatch();
stopwatch.Start();

Thread.Sleep(100);

stopwatch.Stop();

Console.WriteLine($"Total milliseconds: {stopwatch.Elapsed.TotalMilliseconds:F4}"); // Total milliseconds: 108.8356
Console.WriteLine($"Total seconds: {stopwatch.Elapsed.TotalSeconds:F4}"); // Total seconds: 0.1088
Console.WriteLine($"Total minutes: {stopwatch.Elapsed.TotalMinutes:F4}"); // Total minutes: 0.0018

Although both of these classes work with time, we can clearly see that the StopWatch class has a completely different application.

Third-party Alternatives

Let’s have a look at some free third-party libraries that can replace Timer. In general, these options offer an array of advanced features in exchange for some added complexity.

Quartz.NET works embedded in a program or stand-alone. It offers many ways to schedule jobs beyond a simple time interval setup. It can work in clusters, enabling fail-over and load balancing setups.

Hangfire is a job scheduler that tracks jobs in persistent storage ensuring job execution. It schedules jobs based on intervals, like Timer, but also offers many more options like job queues or batches.

Conclusion

In this article, we’ve learned what Timer in C# is and how it works. We’ve practiced creating timer event handlers and how to dispose of our timer instances.

We’ve also learned about the differences between Timer and StopWatch and, finally, we had a look at some popular third-party alternatives.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!