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

C#事件与委托:如何延迟调用事件订阅者并触发后自动移除?

实现延迟触发并自动取消订阅的事件处理程序

我学习了C#的事件与委托,编写了如下基础示例:

public class Subject {
  public delegate void RandomDelegate();
  public event RandomDelegate randomEvent;
  void CallRandom() {
    if (randomEvent != null) {randomEvent();}
  }
}

目前可以通过Subject.randomEvent += randomEventHandler;的方式订阅事件,处理每次触发逻辑。但我需要实现一种延迟事件处理程序:订阅后,仅在第n次触发randomEvent时执行目标逻辑,且执行完成后自动取消订阅。

我尝试编写了DelayedHandler类,但还存在困惑:

public class DelayedHandler
{
    public int CurrentDelay { get; private set; } = 0;
    public int Delay { get; init; }

    public DelayedHandler(int delay)
    {
        Delay = delay;
    }

    public void Handler() // 调用方式:randomEvent += new DelayedHandler().Handler
    {
        if (CurrentDelay >= Delay)
        {
            // 待执行的逻辑
        }
        else
        {
            CurrentDelay++;
        }
    }
}

现有代码的问题

当前的DelayedHandler无法自动取消订阅,因为它没有持有事件的引用,也无法在满足触发条件后从事件中移除自身的委托实例。

解决方案

方案1:使用扩展方法+闭包(简洁灵活)

通过扩展方法封装延迟订阅逻辑,利用闭包维护计数和委托引用,实现自动取消订阅:

public static class SubjectEventExtensions
{
    public static void SubscribeDelayed(this Subject subject, int triggerAfter, Action onTriggered)
    {
        int triggerCount = 0;
        RandomDelegate handler = null;
        
        handler = () =>
        {
            triggerCount++;
            if (triggerCount == triggerAfter)
            {
                onTriggered();
                // 执行完成后取消订阅
                subject.randomEvent -= handler;
            }
        };
        
        subject.randomEvent += handler;
    }
}

使用方式:

var subject = new Subject();
// 订阅第3次触发时执行逻辑
subject.SubscribeDelayed(3, () => Console.WriteLine("延迟触发的逻辑执行了"));

方案2:改进DelayedHandler类(封装性强)

让DelayedHandler持有事件源的引用,在满足条件时主动移除自身委托:

public class DelayedHandler
{
    private int _currentTriggerCount = 0;
    private readonly int _triggerAfter;
    private readonly Subject _eventSource;
    private readonly Action _targetAction;

    public DelayedHandler(Subject eventSource, int triggerAfter, Action targetAction)
    {
        _eventSource = eventSource;
        _triggerAfter = triggerAfter;
        _targetAction = targetAction;
        // 初始化时自动订阅事件
        _eventSource.randomEvent += HandleEvent;
    }

    private void HandleEvent()
    {
        _currentTriggerCount++;
        if (_currentTriggerCount == _triggerAfter)
        {
            _targetAction();
            // 执行后取消订阅
            _eventSource.randomEvent -= HandleEvent;
        }
    }
}

使用方式:

var subject = new Subject();
// 创建Handler实例,自动订阅第3次触发
new DelayedHandler(subject, 3, () => Console.WriteLine("延迟触发的逻辑执行了"));

两种方案都能实现需求:方案1更轻量化,适合快速调用;方案2将逻辑封装在类中,便于状态管理和复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:55:25