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

为何无法为Action创建带ref的this扩展方法?

问题与解决方案

原尝试代码(无法运行)

用户尝试实现一种无需存储委托即可取消订阅的事件模式,但因Action是引用类型,无法作为ref this参数用于扩展方法,代码如下:

public static class Program
{
    public static event Action OnEvent;

    public static void Main()
    {
        var registration = OnEvent.Subscribe(() => { Console.Write("OnEventInvoked"); });
        OnEvent?.Invoke();
        registration.Dispose();
    }

    public static CancellationTokenRegistration Subscribe(ref this Action action, Action callback)
    {
        action += callback;
        return new CancellationToken().Register(() => { action -= callback; });
    }
}

需求说明

  • 通过event修饰符禁止在声明类外部调用事件的Invoke方法;
  • 实现无需存储委托实例即可取消订阅的Subscribe方法;
  • 不能创建包含委托的自定义公开类,避免Invoke方法被外部访问。

可行实现方案

可以通过在事件声明类内部封装订阅逻辑,返回自定义的IDisposable实现来完成需求,既保持事件的封装性,又能便捷取消订阅:

public static class Program
{
    // 私有event确保外部无法直接Invoke或操作委托实例
    private static event Action OnEvent;

    public static void Main()
    {
        // 使用using自动释放,无需手动管理Dispose
        using var registration = Subscribe(() => Console.Write("OnEventInvoked"));
        OnEvent?.Invoke();
    }

    // 公开的订阅方法,返回IDisposable用于取消订阅
    public static IDisposable Subscribe(Action callback)
    {
        OnEvent += callback;
        return new Unsubscriber(() => OnEvent -= callback);
    }

    // 私有内部类实现取消订阅逻辑
    private sealed class Unsubscriber : IDisposable
    {
        private readonly Action _unsubscribeAction;
        private bool _isDisposed;

        public Unsubscriber(Action unsubscribeAction)
        {
            _unsubscribeAction = unsubscribeAction;
        }

        public void Dispose()
        {
            if (!_isDisposed)
            {
                _unsubscribeAction();
                _isDisposed = true;
            }
        }
    }
}

方案说明

  1. 事件封装:将OnEvent设为私有event,外部完全无法调用Invoke,也不能直接操作委托实例,仅能通过类提供的Subscribe方法订阅;
  2. 取消订阅逻辑:Subscribe方法返回自定义的Unsubscriber实例,该实例持有移除委托的逻辑,调用Dispose时自动执行取消订阅;
  3. 使用便捷性:可以配合using语句自动释放,无需手动保存委托实例,满足需求中“无需存储action即可取消订阅”的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:20:31