C# Timer事件取消订阅失效,重复订阅问题求助
解决System.Timers.Timer事件取消订阅无效的问题
问题根源
你当前使用(w, e) => timer_Elapsed(w,e)这类匿名lambda表达式进行事件订阅与取消操作,每次调用updateInfo方法时,这个lambda都会生成全新的委托实例。事件的订阅/取消是基于委托实例的引用匹配实现的,用新的lambda去取消订阅时,无法匹配到之前订阅的委托实例,导致取消操作失效,每次调用都会新增一个事件订阅。
解决方案
方案1:直接使用方法组订阅(推荐)
去掉lambda包装,直接引用timer_Elapsed方法作为事件处理程序,这样每次订阅和取消的都是同一个委托实例:
[Inject] public Timer timer { get; set; } protected override void OnInitialized() { settingsModel = applicationDb.SettingsModal.FirstOrDefault(); updateInfo(); } public async void updateInfo() { try { if (!string.IsNullOrEmpty(settingsModel.Message)) { // 先取消已有订阅(如果存在) timer.Elapsed -= timer_Elapsed; timer.Elapsed += timer_Elapsed; timer.Interval = 3000; timer.Start(); } else { timer.Elapsed -= timer_Elapsed; timer.Stop(); } } catch (Exception e) { ToastService.ShowError(e.Message); } } async void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // do some stuff }
方案2:保存委托实例到字段(需使用lambda时)
如果必须通过lambda捕获变量,可将委托实例保存为类的字段,确保每次订阅/取消都复用同一个实例:
[Inject] public Timer timer { get; set; } // 保存委托实例的字段 private System.Timers.ElapsedEventHandler _timerHandler; protected override void OnInitialized() { settingsModel = applicationDb.SettingsModal.FirstOrDefault(); // 仅初始化一次委托实例 _timerHandler = (w, e) => timer_Elapsed(w, e); updateInfo(); } public async void updateInfo() { try { if (!string.IsNullOrEmpty(settingsModel.Message)) { timer.Elapsed -= _timerHandler; timer.Elapsed += _timerHandler; timer.Interval = 3000; timer.Start(); } else { timer.Elapsed -= _timerHandler; timer.Stop(); } } catch (Exception e) { ToastService.ShowError(e.Message); } } async void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // do some stuff }
额外注意事项
- 用
string.IsNullOrEmpty(settingsModel.Message)替代原有的双重判断,代码更简洁规范 - 非事件处理场景下尽量避免使用
async void,若updateInfo需异步操作,建议返回Task并通过await调用(Blazor组件中需注意异步方法的异常处理) - 调用
updateInfo前可先停止timer,避免操作订阅时触发事件干扰
内容的提问来源于stack exchange,提问作者adel
相关产品推荐
相关产品推荐

