Scenario: I am building a scheduling system and each timer event I wanted to run a custom method instead of the usual Timer.Elapsed
event.
So I wrote something like this.
foreach (ScheduleElement schedule in schedules) {
TimeSpan timeToRun = CalculateTime(schedule);
schedule.Timer = new Timer(timeToRun.TotalMilliseconds);
schedule.Timer.Elapsed += delegate { Refresh_Timer(schedule); };
schedule.Timer.AutoReset = true;
schedule.Timer.Enabled = true;
}
Ok so simple enough that actually did create my timers. However, I wanted each elapsed event to run using the schedule element that it passed in. My question is, why does the Elapsed event only pass in the last ScheduleElement in the for loop for every single Timer.Elapsed event.
Now I know what fixes it, I am just not sure why. If I roll back to the original Timer.Elapsed event and extend the Timer class with my own class I can work around it. Like so.
The Fix:
foreach (ScheduleElement schedule in schedules) {
TimeSpan timeToRun = CalculateTime(schedule);
schedule.Timer = new TimerEx(timeToRun.TotalMilliseconds);
schedule.Timer.Elapsed +=new System.Timers.ElapsedEventHandler(Refresh_Timer);
schedule.Timer.Tag = schedule;
schedule.Timer.AutoReset = true;
schedule.Timer.Enabled = true;
}
I then cast the object sender
back into its original object, and thieve the Tag
property off of it which gives me my correct schedule for each unique timer.
So again, why does using a delegate { }
only pass in the last ScheduleElement
in the foreach loop for all Timers?
EDIT 1
The Timer class
public TimerEx : Timer {
public TimerEx(double interval) : base(interval) { }
private Object _Tag;
public Object Tag {
get { return _Tag; }
set { _Tag = value; }
}
}