boxmoe_header_banner_img

菜就多练喵

文章导读

[C#][Unity][Ib_Core]Ib_Event——以Type为Key的的同步/异步事件中心 v0.5


avatar
Ib_Mccf 2025年11月15日 137

功能:通过全局事件使类与类之间的通信解耦(两个类之间无需知道彼此的存在,类似广播电台,一个类发送,一个类监听)。

特点:使一个类继承Ib_Event即可快速声明一个全局同步事件,支持立即/延迟一帧调用、同步/异步执行、重载了至多五个参数的传入。

性能:在事件注册和注销时会有容器容量变化产生的GC。通过List和脏标记,大量相同事件在同一帧内同时注册或注销会有多次List扩容和一次数组复制扩容带来的GC(在注册后第一次调用时产生),后续调用事件不会产生GC。

可能的缺点:要十分注意事件的注册和注销,尤其是场景切换的时候,不然会内存泄漏。

更新记录:

2025-12-14 v0.3 优化了n个相同事件在同一帧同时注册/注销时,会进行n次数组复制扩容的性能问题。现在每次注册/注销只会List进行扩容,产生微量GC,并在注册后的首次调用时将List转化为数组(n次同时注册只会产生一次数组的扩容)。对异步事件中心进行优化。

2025-12-23 v0.4 使用Ib_Event.InvokeNextFrame()延迟一帧调用事件时,每次都会为Ib_Async.DelayDoSomething()方法传入新的委托实例产生GC。现在使用了一个只读静态委托变量CachedInvokeAction缓存,避免了每次调用的GC。

  public abstract partial class Ib_Event<T, T1, T2> : IIb_Event where T : Ib_Event<T, T1, T2>
    {
        private static readonly Action<T1, T2> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1, T2>;
        public static void InvokeNextFrame(T1 arg1, T2 arg2, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, arg2, cts);
    }

2026-07-30 v0.5 增加Ib_EventListener拓展Listen()方法,支持监听生命周期(OnDestroy,OnDisable)自动取消订阅(Listen中包含Register注册,并在特定生命周期时DeRegister)。

示例:我挂了,使游戏结束。

玩家类:在挂了以后发送OnPlayerDead事件。

//一个类继承Ib_Event,即可新建一个全局事件。这个类不需要任何成员。
public class OnPlayerDead : Ib_Event<OnPlayerDead> { }

public class Sample_Ib_Event_Player : MonoBehaviour
{
    void Start()
    {
        //我在五秒后挂了
        Ib_Async.DelayDoSomething(5,Die,this.GetCancellationTokenOnDestroy());
    }

    void Die()
    {
        Ib_Log.Info($"{GetType().Name} >> 啊,我挂了。");
        //发送我挂了的消息
        OnPlayerDead.Invoke();
    }
}

管理器:监听OnPlayerDead事件,触发后调用GameOver()结束游戏。

//游戏进程的管理器,可以在这里接收玩家挂了的消息。
public class Sample_Ib_Event_GameManager : Ib_Singleton<Sample_Ib_Event_GameManager>
{
    protected override void Awake()
    {
        base.Awake();
        //订阅玩家挂了的事件,如果消息传来,就调用GameOver()方法使游戏结束。
        OnPlayerDead.Register(GameOver);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        //(必须)在生命周期的末尾取消订阅事件,避免内存泄漏。
        OnPlayerDead.Deregister(GameOver);
    }

    //如果玩家挂了,就游戏结束
    void GameOver()
    {
        Ib_Log.Info($"{GetType().Name} >> 玩家挂了,游戏结束");
    }
}

玩家类和管理器类之间并没有任何的相互引用,它们不知道彼此的存在,它们的通信全都由第三方的事件中心来进行接收和转发。这样这两个之间就没有了耦合关系,哪怕管理器类不存在,也不有任何的报错。

Ib_Event也支持参数的传递,如玩家挂了,我需要传递玩家挂了的消息和遗言。管理器的GameOver方法就需要接收传来的string类型遗言,并进行打印。

//一个类继承Ib_Event,即可就新建一个全局事件。这个类不需要任何成员。
public class OnPlayerDead : Ib_Event<OnPlayerDead,string> { }

public class Sample_Ib_Event_Player : MonoBehaviour
{
    void Start()
    {
        //我在五秒后挂了
        Ib_Async.DelayDoSomething(5,Die,this.GetCancellationTokenOnDestroy());
    }

    void Die()
    {
        Ib_Log.Info($"{GetType().Name} >> 啊,我挂了。");
        //发送我挂了的消息
        OnPlayerDead.Invoke("卧槽,我竟然挂了,我不甘心啊");
    }
}
    //如果玩家挂了,就游戏结束
    void GameOver(string message)
    {
        Ib_Log.Info($"遗言 >> {message}");
        Ib_Log.Info($"{GetType().Name} >> 玩家挂了,游戏结束");
    }

核心功能简易实现:

using System;
using System.Collections.Generic;

/// <summary>
/// 事件系统的基础接口(标记接口)。
/// <para>主要用于泛型约束,确保只有实现了该接口的类型才能被注册到事件中心。</para>
/// </summary>
public interface ISample_Ib_Event { }

/// <summary>
/// 事件基类。所有自定义事件需继承此类。使用示例:public class 事件名 : Sample_Ib_Event<事件名> { }
/// <para>使用 CRTP (Curiously Recurring Template Pattern) 模式,简化静态调用。</para>
/// </summary>
/// <typeparam name="T">具体的事件类型(即子类自身)。</typeparam>
public abstract class Sample_Ib_Event<T> : ISample_Ib_Event where T : Sample_Ib_Event<T>
{
    /// <summary>
    /// 触发(广播)事件。
    /// <para>通知所有订阅了该事件的监听者。</para>
    /// </summary>
    public static void Invoke()
    {
        Sample_Ib_EventHandler.Invoke<T>();
    }
    
    /// <summary>
    /// 注册(订阅)事件。
    /// </summary>
    /// <param name="action">事件触发时要执行的回调函数。</param>
    public static void Register(Action action)
    {
        Sample_Ib_EventHandler.Register<T>(action);
    }
  
    /// <summary>
    /// 取消注册(退订)事件。
    /// <para>注意:必须传入与注册时完全相同的委托实例。</para>
    /// </summary>
    /// <param name="action">需要移除的回调函数。</param>
    public static void Deregister(Action action)
    {
        Sample_Ib_EventHandler.Deregister<T>(action);
    }
}

/// <summary>
/// 事件中心(核心管理器)。
/// <para>负责底层存储和分发消息。通常不需要直接调用此类,而是通过继承 <see cref="Sample_Ib_Event{T}"/> 来使用。</para>
/// </summary>
public static class Sample_Ib_EventHandler
{
    // 存储所有事件委托的字典,Key 为事件类型,Value 为多播委托
    private static readonly Dictionary<Type, Action> EventsDict = new();

    /// <summary>
    /// 执行指定类型的事件。
    /// </summary>
    /// <typeparam name="T">必须实现 <see cref="ISample_Ib_Event"/> 的事件类型。</typeparam>
    public static void Invoke<T>() where T : ISample_Ib_Event
    {
        if (EventsDict.TryGetValue(typeof(T), out var action))
        {
            action?.Invoke();
        }
    }

    /// <summary>
    /// 将回调注册到指定类型的事件中。
    /// </summary>
    /// <typeparam name="T">事件类型。</typeparam>
    /// <param name="action">回调委托。</param>
    public static void Register<T>(Action action) where T : ISample_Ib_Event
    {
        Type eventType = typeof(T);
        // 如果字典中不存在该 Key,则添加;如果存在,则使用 += 进行多播委托叠加
        if (!EventsDict.TryAdd(eventType, action))
            EventsDict[eventType] += action;
    }
    
    /// <summary>
    /// 从指定类型的事件中移除回调。
    /// </summary>
    /// <typeparam name="T">事件类型。</typeparam>
    /// <param name="action">要移除的回调委托。</param>
    public static void Deregister<T>(Action action) where T : ISample_Ib_Event
    {
        Type eventType = typeof(T);
        if (EventsDict.ContainsKey(eventType))
        {
            EventsDict[eventType] -= action;
        }
    }
}

同步事件中心源码:


*订阅Register/注销Deregister后首次Invoke会有数组分配,之后的Invoke零分配。

//支持至多五个参数的事件中心。
//使用方法:
//1、声明一个事件类,继承Ib_Event
//  public class OnGameLog : Ib_Event<OnGameLog,string> { };
//2、在Mono类中进行注册与注销
//  Action<string> testAction = (string content)=>Ib_Log.Info(content);
//  OnGameLog.Register(testAction);
//  OnGameLog.Deregister(testAction);
//3、调用
//OnGameLog.Invoke("成功调用");

namespace Ib_Core
{
    using System;
    using System.Collections.Generic;
    internal interface IIb_Event
    {
    }

    #region 无参数事件基类

    public abstract partial class Ib_Event<T> : IIb_Event where T : Ib_Event<T>
    {
        public static void Invoke() => Ib_EventHandler.Invoke<T>();
        public static void Register(Action action) => Ib_EventHandler.Register<T>(action);
        public static void Deregister(Action action) => Ib_EventHandler.Deregister<T>(action);
    }

    #endregion

    #region 单参数事件基类

    public abstract partial class Ib_Event<T, T1> : IIb_Event where T : Ib_Event<T, T1>
    {
        public static void Invoke(T1 arg1) => Ib_EventHandler.Invoke<T, T1>(arg1);
        public static void Register(Action<T1> action) => Ib_EventHandler.Register<T, T1>(action);
        public static void Deregister(Action<T1> action) => Ib_EventHandler.Deregister<T, T1>(action);
    }

    #endregion

    #region 双参数事件基类

    public abstract partial class Ib_Event<T, T1, T2> : IIb_Event where T : Ib_Event<T, T1, T2>
    {
        public static void Invoke(T1 arg1, T2 arg2) => Ib_EventHandler.Invoke<T, T1, T2>(arg1, arg2);
        public static void Register(Action<T1, T2> action) => Ib_EventHandler.Register<T, T1, T2>(action);
        public static void Deregister(Action<T1, T2> action) => Ib_EventHandler.Deregister<T, T1, T2>(action);
    }

    #endregion

    #region 三参数事件基类

    public abstract partial class Ib_Event<T, T1, T2, T3> : IIb_Event where T : Ib_Event<T, T1, T2, T3>
    {
        public static void Invoke(T1 arg1, T2 arg2, T3 arg3) => Ib_EventHandler.Invoke<T, T1, T2, T3>(arg1, arg2, arg3);
        public static void Register(Action<T1, T2, T3> action) => Ib_EventHandler.Register<T, T1, T2, T3>(action);
        public static void Deregister(Action<T1, T2, T3> action) => Ib_EventHandler.Deregister<T, T1, T2, T3>(action);
    }

    #endregion

    #region 四参数事件基类

    public abstract partial class Ib_Event<T, T1, T2, T3, T4> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4>
    {
        public static void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) =>
            Ib_EventHandler.Invoke<T, T1, T2, T3, T4>(arg1, arg2, arg3, arg4);
        public static void Register(Action<T1, T2, T3, T4> action) =>
            Ib_EventHandler.Register<T, T1, T2, T3, T4>(action);

        public static void Deregister(Action<T1, T2, T3, T4> action) =>
            Ib_EventHandler.Deregister<T, T1, T2, T3, T4>(action);
    }

    #endregion

    #region 五参数事件基类

    public abstract partial class Ib_Event<T, T1, T2, T3, T4, T5> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4, T5>
    {
        public static void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) =>
            Ib_EventHandler.Invoke<T, T1, T2, T3, T4, T5>(arg1, arg2, arg3, arg4, arg5);
        public static void Register(Action<T1, T2, T3, T4, T5> action) =>
            Ib_EventHandler.Register<T, T1, T2, T3, T4, T5>(action);
        public static void Deregister(Action<T1, T2, T3, T4, T5> action) =>
            Ib_EventHandler.Deregister<T, T1, T2, T3, T4, T5>(action);
    }

    #endregion

    #region 事件容器

    /// <summary>
    /// 事件容器,使用写时复制(Copy-on-Write)策略来实现 0 GC 的 Invoke
    /// </summary>
    internal class Ib_EventContainer
    {
        // 直接持有数组,Invoke时直接遍历这个数组
        private Delegate[] _actionArray = Array.Empty<Delegate>();
        public bool IsEmpty => _actionList.Count == 0;
        
        //list和脏标记用于防止同一帧内有大量事件同时注册,导致卡顿
        private readonly List<Delegate> _actionList = new List<Delegate>();
        private bool _isDirty = false;//脏标记
        public void Add(Delegate callback)
        {
            if (callback == null) return;
            _actionList.Add(callback);
            _isDirty = true;
        }

        public void Remove(Delegate callback)
        {
            if (callback == null) return;

            if (_actionList.Remove(callback))
            {
                _isDirty = true;
            }
        }
        
        public Delegate[] GetDelegateArray()
        {
            if (_isDirty)
            {
                _actionArray = _actionList.ToArray();
                _isDirty = false;
            }
            return _actionArray;
        }
    }

    #endregion

    internal static partial class Ib_EventHandler
    {
        private static readonly Dictionary<Type, Ib_EventContainer> EventsDict = new();
        private static readonly object _lock = new object();

        // 获取或创建容器的辅助方法
        private static Ib_EventContainer GetContainer(Type type, bool createIfNull)
        {
            if (!EventsDict.TryGetValue(type, out var container))
            {
                if (createIfNull)
                {
                    container = new Ib_EventContainer();
                    EventsDict[type] = container;
                }
            }

            return container;
        }

        #region 无参数的事件处理

        public static void Invoke<T>() where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action)actions[i];
                try
                {
                    action?.Invoke();
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T>(Action action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T>(Action action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion

        #region 单参数的事件处理

        public static void Invoke<T, T1>(T1 arg1) where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action<T1>)actions[i];
                try
                {
                    action?.Invoke(arg1);
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T, T1>(Action<T1> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T, T1>(Action<T1> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion

        #region 双参数的事件处理

        public static void Invoke<T, T1, T2>(T1 arg1, T2 arg2) where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action<T1, T2>)actions[i];
                try
                {
                    action?.Invoke(arg1, arg2);
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T, T1, T2>(Action<T1, T2> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T, T1, T2>(Action<T1, T2> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion

        #region 三参数的事件处理

        public static void Invoke<T, T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action<T1, T2, T3>)actions[i];
                try
                {
                    action?.Invoke(arg1, arg2, arg3);
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T, T1, T2, T3>(Action<T1, T2, T3> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T, T1, T2, T3>(Action<T1, T2, T3> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion

        #region 四参数的事件处理

        public static void Invoke<T, T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4) where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action<T1, T2, T3, T4>)actions[i];
                try
                {
                    action?.Invoke(arg1, arg2, arg3, arg4);
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T, T1, T2, T3, T4>(Action<T1, T2, T3, T4> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T, T1, T2, T3, T4>(Action<T1, T2, T3, T4> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion

        #region 五参数的事件处理

        public static void Invoke<T, T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
            where T : IIb_Event
        {
            Delegate[] actions = null;
            lock (_lock)
            {
                if (EventsDict.TryGetValue(typeof(T), out var container))
                {
                    actions = container.GetDelegateArray();
                }
            }

            if (actions == null || actions.Length == 0) return;

            for (int i = 0; i < actions.Length; i++)
            {
                var action = (Action<T1, T2, T3, T4, T5>)actions[i];
                try
                {
                    action?.Invoke(arg1, arg2, arg3, arg4, arg5);
                }
                catch (Exception ex)
                {
                    Ib_Log.Error($"Error while invoking event {typeof(T).Name}: {ex.Message}\n{ex.StackTrace}");
                }
            }
        }

        public static void Register<T, T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), true);
                container.Add(action);
            }
        }

        public static void Deregister<T, T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action) where T : IIb_Event
        {
            lock (_lock)
            {
                var container = GetContainer(typeof(T), false);
                if (container != null)
                {
                    container.Remove(action);
                    if (container.IsEmpty)
                    {
                        EventsDict.Remove(typeof(T));
                    }
                }
            }
        }

        #endregion
    }
}

Ib_EventListener订阅后自动注销

用处:避免事件订阅后忘记注销,造成内存泄漏

前提:使用类需要继承MonoBehaviour

using Ib_Core;
using Ib_Core.Ib_Controller;

//游戏进程的管理器,可以在这里接收玩家挂了的消息。
public class Sample_Ib_Event_GameManager : Ib_Singleton<Sample_Ib_Event_GameManager>
{
    protected override void Awake()
    {
        base.Awake();
        //使用Listen()订阅,自动管理事件的生命周期
        OnPlayerDead.Listen(GameOver,new ListenConfig(this,Ib_EventListener.EDeregisterLc.OnDestroy));
        //订阅玩家挂了的事件,如果消息传来,就调用GameOver()方法使游戏结束。
        // OnPlayerDead.Register(GameOver);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        //(必须)在生命周期的末尾取消订阅事件,避免内存泄漏。
        // OnPlayerDead.Deregister(GameOver);
    }

    //如果玩家挂了,就游戏结束
    void GameOver(string message)
    {
        Ib_Log.Info($"遗言 >> {message}");
        Ib_Log.Info($"{GetType().Name} >> 玩家挂了,游戏结束");
    }
}


使用Listen()订阅时绑定MonoBehaviour生命周期,自动注销

//事件自动注销拓展:注册事件时绑定 MonoBehaviour 生命周期,到期自动注销,无需手动 Deregister。
//支持 OnDestroy / OnDisable 两种注销时机(EDeregisterLc)。
//OnDisable 为一次性注销:在 OnEnable 中调用 Listen 注册,OnDisable 时自动注销,下次 OnEnable 需重新 Listen。
//零闭包 GC:通过 typeof(T) + Delegate 直传 Tracker,不产生 closure。
//用法:
//1、声明事件类,继承 Ib_Event
//  public class OnPlayerDead : Ib_Event<OnPlayerDead, string> { }
//2、在 MonoBehaviour 中注册(泛型参数自动推导,无需手写)
//  void OnEnable()
//  {
//      OnPlayerDead.Listen(OnPlayerDeadHandler, new ListenConfig(this, Ib_EventListener.EDeregisterLc.OnDisable));
//  }
//  void OnPlayerDeadHandler(string killer) { ... }
//3、调用
//  OnPlayerDead.Invoke("Boss");

namespace Ib_Core
{
    using System;
    using UnityEngine;

    public static class Ib_EventListener
    {
        public enum EDeregisterLc
        {
            OnDestroy,
            OnDisable
        }

        internal static void AddToTracker(MonoBehaviour owner, Type type, Delegate action, EDeregisterLc deregisterLc)
        {
            if (!owner.TryGetComponent(out Ib_EventLifecycleTracker tracker))
                tracker = owner.gameObject.AddComponent<Ib_EventLifecycleTracker>();
            switch (deregisterLc)
            {
                case EDeregisterLc.OnDestroy:
                default:
                    tracker.Add2Destroy(type, action);
                    break;
                case EDeregisterLc.OnDisable:
                    tracker.Add2Disable(type, action);
                    break;
            }
        }

        internal static void AddMessengerToTracker(MonoBehaviour owner, int hash, Delegate action, EDeregisterLc deregisterLc)
        {
            if (!owner.TryGetComponent(out Ib_EventLifecycleTracker tracker))
                tracker = owner.gameObject.AddComponent<Ib_EventLifecycleTracker>();
            switch (deregisterLc)
            {
                case EDeregisterLc.OnDestroy:
                default:
                    tracker.AddMessenger2Destroy(hash, action);
                    break;
                case EDeregisterLc.OnDisable:
                    tracker.AddMessenger2Disable(hash, action);
                    break;
            }
        }
    }

    internal static partial class Ib_EventHandler
    {
        public static void Deregister(Type eventType, Delegate action)
        {
            var container = GetContainer(eventType, false);
            if (container != null)
            {
                container.Remove(action);
                if (container.IsEmpty)
                {
                    EventsDict.Remove(eventType);
                }
            }
        }
    }

    public struct ListenConfig
    {
        public MonoBehaviour Listener;
        public Ib_EventListener.EDeregisterLc DeregisterLc;
        public ListenConfig(MonoBehaviour listener, Ib_EventListener.EDeregisterLc deregisterLc)
        {
            Listener = listener;
            DeregisterLc = deregisterLc;
        }
    }

    public abstract partial class Ib_Event<T> : IIb_Event where T : Ib_Event<T>
    {
        public static void Listen(Action action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T>(action);
        }
    }

    public abstract partial class Ib_Event<T, T1> : IIb_Event where T : Ib_Event<T, T1>
    {
        public static void Listen(Action<T1> action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T, T1>(action);
        }
    }

    public abstract partial class Ib_Event<T, T1, T2> : IIb_Event where T : Ib_Event<T, T1, T2>
    {
        public static void Listen(Action<T1, T2> action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T, T1, T2>(action);
        }
    }

    public abstract partial class Ib_Event<T, T1, T2, T3> : IIb_Event where T : Ib_Event<T, T1, T2, T3>
    {
        public static void Listen(Action<T1, T2, T3> action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T, T1, T2, T3>(action);
        }
    }

    public abstract partial class Ib_Event<T, T1, T2, T3, T4> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4>
    {
        public static void Listen(Action<T1, T2, T3, T4> action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T, T1, T2, T3, T4>(action);
        }
    }

    public abstract partial class Ib_Event<T, T1, T2, T3, T4, T5> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4, T5>
    {
        public static void Listen(Action<T1, T2, T3, T4, T5> action, ListenConfig listenConfig)
        {
            Ib_EventListener.AddToTracker(listenConfig.Listener, typeof(T), action, listenConfig.DeregisterLc);
            Ib_EventHandler.Register<T, T1, T2, T3, T4, T5>(action);
        }
    }
}
using System;
using System.Collections.Generic;
using Ib_Core;
using UnityEngine;

// 隐藏组件,挂在 owner 的 GameObject 上
// 同时支持 Ib_Event (Type key) 和 Ib_Messenger (int hash key) 的自动注销
internal class Ib_EventLifecycleTracker : MonoBehaviour
{
    List<(Type eventType, Delegate dlg)> _destroyEntries;
    List<(Type eventType, Delegate dlg)> _disableEntries;
    List<(int hash, Delegate dlg)> _messengerDestroyEntries;
    List<(int hash, Delegate dlg)> _messengerDisableEntries;

    void OnDestroy()
    {
        if (_destroyEntries != null)
        {
            foreach (var (type, dlg) in _destroyEntries)
                Ib_EventHandler.Deregister(type, dlg);
            _destroyEntries.Clear();
        }
        if (_messengerDestroyEntries != null)
        {
            foreach (var (hash, dlg) in _messengerDestroyEntries)
                Ib_Messenger.Deregister(hash, dlg);
            _messengerDestroyEntries.Clear();
        }
    }

    public void Add2Destroy(Type type, Delegate action)
    {
        if (_destroyEntries == null) _destroyEntries = new();
        _destroyEntries.Add((type, action));
    }

    public void Add2Disable(Type type, Delegate action)
    {
        if (_disableEntries == null) _disableEntries = new();
        _disableEntries.Add((type, action));
    }

    public void AddMessenger2Destroy(int hash, Delegate action)
    {
        if (_messengerDestroyEntries == null) _messengerDestroyEntries = new();
        _messengerDestroyEntries.Add((hash, action));
    }

    public void AddMessenger2Disable(int hash, Delegate action)
    {
        if (_messengerDisableEntries == null) _messengerDisableEntries = new();
        _messengerDisableEntries.Add((hash, action));
    }

    void OnDisable()
    {
        if (_disableEntries != null)
        {
            foreach (var (type, dlg) in _disableEntries)
                Ib_EventHandler.Deregister(type, dlg);
            _disableEntries.Clear();
        }
        if (_messengerDisableEntries != null)
        {
            foreach (var (hash, dlg) in _messengerDisableEntries)
                Ib_Messenger.Deregister(hash, dlg);
            _messengerDisableEntries.Clear();
        }
    }
}

延迟一帧调用拓展:

    #region 零参数事件基类延迟拓展

    public abstract partial class Ib_Event<T> : IIb_Event where T : Ib_Event<T>
    {
        private static readonly Action CachedInvokeAction = Ib_EventHandler.Invoke<T>;
        public static void InvokeNextFrame(CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, cts);
    }

    #endregion

    #region 单参数事件基类延迟拓展

    public abstract partial class Ib_Event<T, T1> : IIb_Event where T : Ib_Event<T, T1>
    {
        private static readonly Action<T1> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1>;
        public static void InvokeNextFrame(T1 arg1, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, cts);
    }

    #endregion

    #region 双参数事件基类延迟拓展

    public abstract partial class Ib_Event<T, T1, T2> : IIb_Event where T : Ib_Event<T, T1, T2>
    {
        private static readonly Action<T1, T2> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1, T2>;
        public static void InvokeNextFrame(T1 arg1, T2 arg2, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, arg2, cts);
    }

    #endregion

    #region 三参数事件基类延迟拓展

    public abstract partial class Ib_Event<T, T1, T2, T3> : IIb_Event where T : Ib_Event<T, T1, T2, T3>
    {
        private static readonly Action<T1, T2, T3> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1, T2, T3>;
        public static void InvokeNextFrame(T1 arg1, T2 arg2, T3 arg3, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, arg2, arg3, cts);
    }

    #endregion

    #region 四参数事件基类延迟拓展

    public abstract partial class Ib_Event<T, T1, T2, T3, T4> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4>
    {
        private static readonly Action<T1, T2, T3, T4> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1, T2, T3, T4>;
        public static void InvokeNextFrame(T1 arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, arg2, arg3, arg4, cts);
    }

    #endregion

    #region 五参数事件基类延迟拓展

    public abstract partial class Ib_Event<T, T1, T2, T3, T4, T5> : IIb_Event where T : Ib_Event<T, T1, T2, T3, T4, T5>
    {
        private static readonly Action<T1, T2, T3, T4, T5> CachedInvokeAction = Ib_EventHandler.Invoke<T, T1, T2, T3, T4, T5>;
        public static void InvokeNextFrame(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken cts) => Ib_Async.DelayDoSomething(0, CachedInvokeAction, arg1, arg2, arg3, arg4, arg5, cts);
    }

    #endregion


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码