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

事件处理管理新手疑问:重复添加/移除委托及订阅列表查询

C#事件订阅与移除的常见问题解答

场景一

_manager.InputOkHandler += InputHandler; // 向事件添加InputHandler
...
_manager.InputOkHandler += InputHandler; // 再次向事件添加同一个InputHandler (1)
...
_manager.InputOkHandler -= InputHandler; // 从事件中移除InputHandler (2)

场景二

_manager.InputOkHandler += InputHandler; // 向事件添加InputHandler
...
_manager.InputOkHandler -= InputHandler; // 从事件中移除InputHandler
...
_manager.InputOkHandler -= InputHandler; // 再次从事件中移除InputHandler (3)

问题解答

  • (1):InputHandler会被添加两次。这意味着当InputOkHandler事件触发时,InputHandler方法会被连续执行两次。
  • (2):只会移除一个InputHandler。每一次+=都是添加一次独立订阅,对应的-=仅移除其中一次订阅,此时事件触发时InputHandler仍会执行一次。
  • (3):不会引发Exception。C#中尝试移除不存在的事件订阅是安全操作,不会抛出异常,程序会正常运行。

如何查看事件的所有已订阅函数?

默认情况下事件的订阅列表是类的内部细节,外部无法直接访问,可通过以下两种方式实现:

  • 修改事件所在类的代码:在类中添加公开方法返回调用列表,示例:
    public Delegate[] GetInputOkSubscribers()
    {
        return InputHandler?.GetInvocationList() ?? Array.Empty<Delegate>();
    }
    
    调用该方法即可获取所有订阅的方法委托。
  • 使用反射(无需修改类代码):通过反射找到事件对应的后备字段,获取委托实例后调用GetInvocationList(),示例:
    FieldInfo field = _manager.GetType().GetField("InputOkHandler", BindingFlags.Instance | BindingFlags.NonPublic);
    if (field != null)
    {
        Delegate handler = field.GetValue(_manager) as Delegate;
        if (handler != null)
        {
            Delegate[] subscribers = handler.GetInvocationList();
            // 遍历subscribers即可查看所有订阅方法
        }
    }
    
    注意:这种方式依赖类内部字段命名,显式实现的事件可能需要调整字段名匹配规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:55:16