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.
CodePudding user response:
The reason is that you use the loop variable i in the timer callback, which is always 4 after the loop, so causing that exception. You should use the Timer instance passed:
timers[i].Elapsed = (o, e) =>
{
Console.WriteLine($"Timer {o} is running");
};
However, that doesn't make much sense since Timer.ToString will just output it's type.
If you want a meaningful output you could make your own NamedTimer class:
public class NamedTimer : System.Timers.Timer
{
public string Name { get; }
public NamedTimer(double interval, string name): base(interval)
{
this.Name = name;
}
public override string ToString() => Name;
}
You use it in this way:
NamedTimer[] timers = new NamedTimer[timersLength];
for (int i = 0; i < timersLength; i )
{
timers[i] = new NamedTimer(interval, (i 1).ToString());
timers[i].Elapsed = (o, e) =>
{
Console.WriteLine($"Timer {o} is running");
};
}
CodePudding user response:
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
Elapsedevent handler will be called by passing thesenderobject - The
sender's type isobjectso you need to cast it toTimer - That object can be used to do the look up in the
timerscollection - Since yo don't use the
EventArgsof theElapsedI suggest to use the discard operator there to express your intent more clearly
