C# System.Timers.Timer array countdown

569 views Asked by At
static void Main()
{
    int timersLength = 4;
    int interval = 1000;
    int[] timerNum = new int[timersLength];
    Timer[] timers = new Timer[timersLength];

    for (int i = 0; i < timersLength; i++)
    {
        timerNum[i] = i;
        timers[i] = new Timer(interval);
        //Console.WriteLine($"Timer {timerNum[i]} is running");
        timers[i].Elapsed += (o, e) =>
        {
            Console.WriteLine($"Timer {timerNum[i]} is running");
        };
    }

    foreach (Timer timer in timers)
        timer.Start();

    Console.ReadKey();
}

whenever I'm trying to make a countdown to the Timer array it gives an

"System.IndexOutOfRangeException: 'Index was outside the bounds of the array."

on the Elapsed line:

timers[i].Elapsed += (o, e) =>
{
    Console.WriteLine($"Timer {timerNum[i]} is running");
};

The code seems fine but for some reason it gives this error.

1

There are 1 answers

2
Peter Csala On

If you don't want to create a class to store the name of the Timer next to it then you can simply create a Dictionary<Timer, string> collection for mapping.

Dictionary<Timer, string> timers = new Dictionary<Timer, string>(timersLength);

for (int i = 0; i < timersLength; i++)
{
    var timer = new Timer(interval);
    timers[timer] = $"Timer {i}";
    timer.Elapsed += (sender, _) => Console.WriteLine($"{timers[(Timer)sender]} is running");
}

foreach (KeyValuePair<Timer, string> mapping in timers)
    mapping.Key.Start();
  • The Elapsed event handler will be called by passing the sender object
  • The sender's type is object so you need to cast it to Timer
  • That object can be used to do the look up in the timers collection
  • Since yo don't use the EventArgs of the Elapsed I suggest to use the discard operator there to express your intent more clearly