C# Windows Service多定时器问题:基于动态List创建的定时器仅最后一个生效的解决方法问询
解决Windows服务中仅最后一个定时器工作的问题
嘿,这个问题我之前也踩过坑——典型的C# foreach循环变量捕获陷阱!
问题根源
在旧版本的C#(C# 5之前)里,foreach循环的迭代变量item是在循环体外声明的,整个循环过程中共用同一个变量引用。你在循环里创建的每个定时器,它们的事件处理程序都会捕获这个共享的item变量。等循环执行完,所有定时器捕获的引用都指向了列表的最后一个元素,自然只有最后一个定时器能正常工作。
快速修复方案
最直接的解决办法是在循环内部创建当前元素的局部副本,让每个定时器捕获这个独立的局部变量:
protected override void OnStart(string[] args) { //** CARICA CONFIGURAZIONI **// List<Configurazione> Configurazioni = ModulReader.GetModulCopyDirectory(); int i = 0; foreach (var item in Configurazioni ) { i++; // 关键步骤:创建当前item的局部副本 var currentItem = item; string data = string.Format("CONFIGURAZIONE {0}",i.ToString()); string folder = @"C:\temp\OUT\"; string fileName = "Test.txt"; string fullPath = folder + fileName; File.AppendAllText(fullPath, data); var timer = new CustomTimer { Interval = Int32.Parse(currentItem.TIMER.Trim()), configurazione = currentItem }; timer.Elapsed += Lavorazione; timer.Start(); } }
如果你用的是C# 5及以上版本(VS2012或更高),也可以改用for循环遍历列表,这样每个迭代的变量都是独立的:
protected override void OnStart(string[] args) { List<Configurazione> Configurazioni = ModulReader.GetModulCopyDirectory(); for (int i = 0; i < Configurazioni.Count; i++) { var currentItem = Configurazioni[i]; string data = string.Format("CONFIGURAZIONE {0}", (i+1).ToString()); // 后续代码和上面一致,使用currentItem代替item string folder = @"C:\temp\OUT\"; string fileName = "Test.txt"; string fullPath = folder + fileName; File.AppendAllText(fullPath, data); var timer = new CustomTimer { Interval = Int32.Parse(currentItem.TIMER.Trim()), configurazione = currentItem }; timer.Elapsed += Lavorazione; timer.Start(); } }
额外优化建议
为了避免服务停止时的内存泄漏,建议把所有创建的定时器保存到一个类级别的集合中,在OnStop方法里统一清理:
- 在类中添加一个私有列表:
private List<CustomTimer> _activeTimers = new List<CustomTimer>();
- 在创建定时器时添加到列表:
var timer = new CustomTimer { Interval = Int32.Parse(currentItem.TIMER.Trim()), configurazione = currentItem }; timer.Elapsed += Lavorazione; timer.Start(); _activeTimers.Add(timer); // 添加到列表
- 在
OnStop方法中清理定时器:
protected override void OnStop() { foreach (var timer in _activeTimers) { timer.Stop(); timer.Elapsed -= Lavorazione; // 移除事件绑定 timer.Dispose(); // 释放资源 } _activeTimers.Clear(); }
这样修改后,所有定时器应该都能正常触发各自的任务了。
内容的提问来源于stack exchange,提问作者FSciacca
相关产品推荐
相关产品推荐

