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

泛型数量可变的自定义事件系统:如何设计通用基类?

问题描述

我实现了一个可同时触发本地事件与网络事件的自定义事件系统,该系统基于Action,需支持最多16个泛型参数(如Event、Event<T>、Event<T1,T2>等)。当前采用硬编码所有可能泛型类的方式实现(代码示例如下),但希望通过基类或接口统一管理这些类,却因泛型参数数量不同,无法确定基类/接口的设计方式。请问是否有可行方案?还是只能保持当前硬编码的实现方式?

public class Event
{
    private Action eventAction = delegate {  };
    
    public void Subscribe(Action function) => eventAction += function;
    public void Unsubscribe(Action function) => eventAction -= function;
    public void Invoke(bool invokeNetworkEvent = false)
    {
        // 触发本地事件
        eventAction?.Invoke();

        if (!invokeNetworkEvent) return;
        // 触发网络事件
    }
}

public class Event<T1>
{
    private Action<T1> eventAction = delegate(T1 _obj1) {  };

    public void Subscribe(Action<T1> function) => eventAction += function;
    public void Unsubscribe(Action<T1> function) => eventAction -= function;
    public void Invoke(T1 _param1, bool invokeNetworkEvent = false)
    {
        // 触发本地事件
        eventAction?.Invoke(_param1);
        
        if (!invokeNetworkEvent) return;
        // 触发网络事件
    }
}

public class Event<T1, T2>
{
    private Action<T1, T2> eventAction = delegate(T1 _obj1, T2 _obj2) {  };

    public void Subscribe(Action<T1, T2> function) => eventAction += function;
    public void Unsubscribe(Action<T1, T2> function) => eventAction -= function;
    public void Invoke(T1 _param1, T2 _param2, bool invokeNetworkEvent = false)
    {
        // 触发本地事件
        eventAction?.Invoke(_param1, _param2);
        
        if (!invokeNetworkEvent) return;
        // 触发网络事件
    }
}
可行方案

1. 非泛型基类复用核心逻辑

提取所有Event类的共性(比如网络事件触发逻辑),定义一个抽象基类,让所有泛型Event类继承它,避免重复代码:

public abstract class BaseEvent
{
    // 统一实现网络事件触发逻辑,所有子类复用
    protected void InvokeNetwork()
    {
        // 网络事件触发的通用代码
    }

    // 暴露给子类的本地事件触发抽象方法
    protected abstract void InvokeLocal();

    // 统一的对外Invoke入口
    public void Trigger(bool invokeNetworkEvent = false)
    {
        InvokeLocal();
        if (invokeNetworkEvent)
        {
            InvokeNetwork();
        }
    }
}

然后每个泛型Event类继承BaseEvent,实现InvokeLocal并处理自身的泛型逻辑:

public class Event : BaseEvent
{
    private Action _eventAction = delegate { };

    public void Subscribe(Action function) => _eventAction += function;
    public void Unsubscribe(Action function) => _eventAction -= function;

    protected override void InvokeLocal()
    {
        _eventAction?.Invoke();
    }

    // 保持原有调用习惯的重载
    public void Invoke(bool invokeNetworkEvent = false)
    {
        Trigger(invokeNetworkEvent);
    }
}

public class Event<T1> : BaseEvent
{
    private Action<T1> _eventAction = delegate(T1 _) { };
    private T1 _currentParam;

    public void Subscribe(Action<T1> function) => _eventAction += function;
    public void Unsubscribe(Action<T1> function) => _eventAction -= function;

    protected override void InvokeLocal()
    {
        _eventAction?.Invoke(_currentParam);
    }

    public void Invoke(T1 param1, bool invokeNetworkEvent = false)
    {
        _currentParam = param1;
        Trigger(invokeNetworkEvent);
    }
}

这种方式能复用网络触发逻辑,同时让所有Event类统一继承自BaseEvent,方便后续统一管理(比如存入集合、批量操作)。

2. 代码生成器自动生成泛型类

由于最多需要16个泛型参数,手动编写所有类过于繁琐,可以使用T4模板或Roslyn代码生成器自动生成从0到16个泛型参数的Event类。

比如用T4模板循环生成不同泛型版本的类,替换参数数量、泛型类型列表、Action类型等重复部分,一次生成所有需要的代码,既避免手动硬编码的工作量,又能保持强类型特性。

3. 动态参数封装(不推荐强类型场景)

如果可以接受弱类型,可以用object[]传递参数,定义单个非泛型Event类:

public class DynamicEvent
{
    private Action<object[]> _eventAction = delegate { };

    public void Subscribe(Action<object[]> function) => _eventAction += function;
    public void Unsubscribe(Action<object[]> function) => _eventAction -= function;

    public void Invoke(bool invokeNetworkEvent = false, params object[] args)
    {
        _eventAction?.Invoke(args);
        if (invokeNetworkEvent)
        {
            // 网络事件触发逻辑,传递args
        }
    }
}

但这种方式会丢失强类型检查,调用时需要手动装箱拆箱,仅适合对类型要求较低的场景,不符合你基于Action的强类型系统需求,因此不推荐。

结论

如果要保留强类型特性,最优方案是非泛型基类复用核心逻辑 + 代码生成器自动生成泛型类,既避免手动硬编码的繁琐,又能保证类型安全。如果不想引入代码生成工具,用基类复用逻辑也能大幅减少重复代码,比纯硬编码更优。

内容的提问来源于stack exchange,提问作者Meister der Magie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:00:49