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

如何消除TaskCanceledException,实现事件触发后延迟执行并重启延迟

实现事件延迟触发并重置延迟的解决方案

需求:当事件触发时,延迟一段时间后执行目标方法,且后续触发的事件需要重置这个延迟。例如滚动条位置变化时,需在用户停止滚动1秒后更新视图。

尝试用Task.Delay+ContinueWith+取消令牌实现第一种方案时,后续调用函数会抛出TaskCanceledException异常,以下是修复后的可行版本,同时附上已验证可用的替代方案。

原第一种方案代码

private CancellationTokenSource? _cts;

private async void Update()
{
    _cts?.Cancel();
    _cts = new();
    await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token)
       .ContinueWith(o => Debug.WriteLine("Update now!"), 
       TaskContinuationOptions.OnlyOnRanToCompletion);
}

修复后的第一种方案代码

private CancellationTokenSource? _cts;

private async void Update()
{
    _cts?.Cancel();
    using var newCts = new CancellationTokenSource();
    _cts = newCts;

    try
    {
        await Task.Delay(TimeSpan.FromSeconds(1), newCts.Token);
        if (!newCts.Token.IsCancellationRequested)
        {
            Debug.WriteLine("Update now!");
        }
    }
    catch (TaskCanceledException)
    {
        // 捕获预期的取消异常,无需额外处理
    }
    finally
    {
        if (_cts == newCts)
        {
            _cts = null;
        }
    }
}

修复要点

  • 用using声明自动管理CancellationTokenSource的生命周期,避免资源泄漏
  • 捕获TaskCanceledException,阻止异常扩散到全局
  • 执行目标方法前检查令牌状态,确保只有未被取消的延迟任务才会触发逻辑
  • 在finally块中清理_cts引用,避免后续操作访问已释放的对象

可行的替代方案代码

private CancellationTokenSource? _cts;
private CancellationTokenRegistration? _cancellationTokenRegistration;

private void Update()
{
    _cancellationTokenRegistration?.Unregister();
    _cts = new();
    _cancellationTokenRegistration = _cts.Token.Register(() => Debug.WriteLine("Update now!"));
    _cts.CancelAfter(1000);
}

替代方案逻辑

每次触发事件时,先取消之前的回调注册,再创建新的CancellationTokenSource,注册目标方法后设置1秒延迟取消。当延迟结束令牌被取消时,自动执行注册的回调方法,全程不会抛出取消异常,实现逻辑更简洁。

内容的提问来源于stack exchange,提问作者radoslawik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:46:01