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

Unity C#使用自定义事件子类时方法组转Action<EventManager.Event>报错问询

问题原因

你理解的「子类实例可赋值给父类引用」的规则不适用于泛型委托的类型转换:
Action<EventManager.Event>要求绑定的方法可以接收所有继承自EventManager.Event的实例作为参数,但你的ZoomEventHandler仅能接收PinchScale.ZoomEvent类型的参数,若允许转换,当其他继承自EventManager.Event的事件实例传入方法时会触发运行时错误,因此C#编译器直接禁止了该转换,这就是CS1503报错的根源。

解决方案

有两种常用实现方案,可按需选择:

方案1:少量修改现有逻辑,注册时封装委托

不需要改动EventManager的核心代码,仅在注册监听时用Lambda做一层类型转换即可,修改Earth.cs的注册代码:

void Start() {
    EventManager.StartListening(PinchScale.ZOOM_EVENT, e => ZoomEventHandler((PinchScale.ZoomEvent)e));
}

修改后你的事件处理函数就可以直接用子类参数:

void ZoomEventHandler(PinchScale.ZoomEvent e)
{
    this.LoadTiles(e.zoomLevel);
}

该方案改造成本极低,适合不想调整原有EventManager架构的场景。

方案2:重构EventManager为泛型版本,彻底消除强制转换

对EventManager做少量改造,用泛型方法自动处理类型转换,不需要手动传事件类型字符串,也不需要任何显式强转:

修改EventManager核心代码

// 新增泛型注册方法
public static void StartListening<T>(Action<T> listener) where T : Event
{
    if (!instance)
    {
        Debug.LogError("EventManager has not been initted. Is there one added to your scene yet?");
        return;
    }
    string eventType = typeof(T).FullName;
    // 自动封装转换逻辑
    Action<Event> wrappedListener = e =>
    {
        if (e is T typedEvent) listener(typedEvent);
    };
    instance.eventDictionary.Add(new EventListenerPair(eventType, wrappedListener));
}

// 新增泛型触发方法(也可以沿用原有TriggerEvent,只需保证事件的type和typeof(T).FullName一致即可)
public static void TriggerEvent<T>(T e) where T : Event
{
    if (instance == null || instance.eventDictionary.Count <= 0) return;
    string eventType = typeof(T).FullName;
    foreach (var pair in instance.eventDictionary.ToArray())
    {
        if (pair.eventType == eventType) pair.listener(e);
    }
}

对应修改使用代码

  1. 定义事件时不需要再手动指定type:
public class ZoomEvent : EventManager.Event
{
    public int zoomLevel;
    public ZoomEvent(int zoomLevel = 0) : base(typeof(ZoomEvent).FullName)
    {
        this.zoomLevel = zoomLevel;
    }
}
  1. 触发事件:
int zoomLevel = Random.Range(1, 10);
EventManager.TriggerEvent(new ZoomEvent(zoomLevel));
  1. 注册监听和处理事件:
void Start() {
    EventManager.StartListening<ZoomEvent>(ZoomEventHandler);
}

void ZoomEventHandler(ZoomEvent e)
{
    this.LoadTiles(e.zoomLevel);
}

该方案后续使用更便捷,类型安全,适合长期维护的项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:45:03