You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:10:36