unity的事件与委托框架

本文详细介绍了如何在C#中使用委托和接口实现事件机制,包括定义多种类型的委托、通过接口封装事件、添加和移除事件监听以及广播事件的过程。

1.定义委托

namespace Framework.Notify
{
    public delegate void NotifyCallback();
    public delegate void NotifyCallback<T>(T arg);
    public delegate void NotifyCallback<T, X>(T arg1, X arg2);
    public delegate void NotifyCallback<T, X, Y>(T arg1, X arg2, Y arg3);
    public delegate void NotifyCallback<T, X, Y, Z>(T arg1, X arg2, Y arg3, Z arg4);
}

2.用接口封装事件的方法 

namespace Framework.Notify
{
    /// <summary>
    /// 事件模块接口
    /// </summary>
    public interface INotifyModule
    {
        /// <summary>
        /// 添加事件监听
        /// </summary>
        /// <param name="eventName">事件名</param>
        /// <param name="callBack">事件回调</param>
		void On(string eventName, NotifyCallback callBack);
        void On<T>(string eventName, NotifyCallback<T> callBack);
        void On<T, X>(string eventName, NotifyCallback<T, X> callBack);
        void On<T, X, Y>(string eventName, NotifyCallback<T, X, Y> callBack);
        void On<T, X, Y, Z>(string eventName, NotifyCallback<T, X, Y, Z> callBack);

        /// <summary>
        /// 移除事件监听
        /// </summary>
        /// <param name="eventName">事件名</param>
        /// <param name="callBack">事件回调</param>
        void Off(string eventName, NotifyCallback callBack);
        void Off<T>(string eventName, NotifyCallback<T> callBack);
        void Off<T, X>(string eventName, NotifyCallback<T, X> callBack);
        void Off<T, X, Y>(string eventName, NotifyCallback<T, X, Y> callBack);
        void Off<T, X, Y, Z>(string eventName, NotifyCallback<T, X, Y, Z> callBack);

        /// <summary>
        /// 广播事件
        /// </summary>
        /// <param name="eventName">事件名</param>
        void Fire(string eventName);
        void Fire<T>(string eventName, T arg);
        void Fire<T, X>(string eventName, T arg1, X arg2);
        void Fire<T, X, Y>(string eventName, T arg1, X arg2, Y arg3);
        void Fire<T, X, Y, Z>(string eventName, T arg1, X arg2, Y arg3, Z arg4);
    }
}

3.事件和委托的主逻辑,这是一个多播委托,通过"+"和"-"的操作添加和移除委托

using System;
using System.Collections.Generic;

namespace Framework.Notify
{
    /// <summary>
    /// 事件模块
    /// </summary>
    public sealed partial class NotifyModule : INotifyModule
    {
        private static Dictionary<string, Delegate> m_EventDic = new Dictionary<string, Delegate>();

        // 监听事件
        public void On(string eventName, NotifyCallback callBack)
        {
            Create(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback)m_EventDic[eventName] + callBack;
        }

        public void On<T>(string eventName, NotifyCallback<T> callBack)
        {
            Create(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T>)m_EventDic[eventName] + callBack;
        }

        public void On<T, X>(string eventName, NotifyCallback<T, X> callBack)
        {
            Create(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X>)m_EventDic[eventName] + callBack;
        }

        public void On<T, X, Y>(string eventName, NotifyCallback<T, X, Y> callBack)
        {
            Create(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X, Y>)m_EventDic[eventName] + callBack;
        }

        public void On<T, X, Y, Z>(string eventName, NotifyCallback<T, X, Y, Z> callBack)
        {
            Create(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X, Y, Z>)m_EventDic[eventName] + callBack;
        }

        // 移除事件
        public void Off(string eventName, NotifyCallback callBack)
        {
            RemoveCheck(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback)m_EventDic[eventName] - callBack;
            Remove(eventName);
        }

        public void Off<T>(string eventName, NotifyCallback<T> callBack)
        {
            RemoveCheck(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T>)m_EventDic[eventName] - callBack;
            Remove(eventName);
        }

        public void Off<T, X>(string eventName, NotifyCallback<T, X> callBack)
        {
            RemoveCheck(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X>)m_EventDic[eventName] - callBack;
            Remove(eventName);
        }

        public void Off<T, X, Y>(string eventName, NotifyCallback<T, X, Y> callBack)
        {
            RemoveCheck(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X, Y>)m_EventDic[eventName] - callBack;
            Remove(eventName);
        }

        public void Off<T, X, Y, Z>(string eventName, NotifyCallback<T, X, Y, Z> callBack)
        {
            RemoveCheck(eventName, callBack);
            m_EventDic[eventName] = (NotifyCallback<T, X, Y, Z>)m_EventDic[eventName] - callBack;
            Remove(eventName);
        }

        // 广播事件
        public void Fire(string eventName)
        {
            Delegate d;
            if (m_EventDic.TryGetValue(eventName, out d))
            {
                NotifyCallback callBack = d as NotifyCallback;
                if (callBack != null)
                {
                    callBack.Invoke();
                }
                else
                {
                    throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventName));
                }
            }
        }

        public void Fire<T>(string eventName, T arg)
        {
            Delegate d;
            if (m_EventDic.TryGetValue(eventName, out d))
            {
                NotifyCallback<T> callBack = d as NotifyCallback<T>;
                if (callBack != null)
                {
                    callBack.Invoke(arg);
                }
                else
                {
                    throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventName));
                }
            }
        }

        public void Fire<T, X>(string eventName, T arg1, X arg2)
        {
            Delegate d;
            if (m_EventDic.TryGetValue(eventName, out d))
            {
                NotifyCallback<T, X> callBack = d as NotifyCallback<T, X>;
                if (callBack != null)
                {
                    callBack.Invoke(arg1, arg2);
                }
                else
                {
                    throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventName));
                }
            }
        }

        public void Fire<T, X, Y>(string eventName, T arg1, X arg2, Y arg3)
        {
            Delegate d;
            if (m_EventDic.TryGetValue(eventName, out d))
            {
                NotifyCallback<T, X, Y> callBack = d as NotifyCallback<T, X, Y>;
                if (callBack != null)
                {
                    callBack.Invoke(arg1, arg2, arg3);
                }
                else
                {
                    throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventName));
                }
            }
        }

        public void Fire<T, X, Y, Z>(string eventName, T arg1, X arg2, Y arg3, Z arg4)
        {
            Delegate d;
            if (m_EventDic.TryGetValue(eventName, out d))
            {
                NotifyCallback<T, X, Y, Z> callBack = d as NotifyCallback<T, X, Y, Z>;
                if (callBack != null)
                {
                    callBack.Invoke(arg1, arg2, arg3, arg4);
                }
                else
                {
                    throw new Exception(string.Format("广播事件错误:事件{0}对应委托具有不同的类型", eventName));
                }
            }
        }

        /// <summary>
        /// 添加事件
        /// </summary>
        /// <param name="eventName">事件名</param>
        /// <param name="callBack">事件回调</param>
        private static void Create(string eventName, Delegate callBack)
        {
            if (!m_EventDic.ContainsKey(eventName))
            {
                m_EventDic.Add(eventName, null);
            }
            Delegate d = m_EventDic[eventName];
            if (d != null && d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("尝试为事件{0}添加不同类型的委托,当前事件所对应的委托是{1},要添加的委托类型为{2}", eventName, d.GetType(), callBack.GetType()));
            }
        }

        private static void RemoveCheck(string eventName, Delegate callBack)
        {
            if (m_EventDic.ContainsKey(eventName))
            {
                Delegate d = m_EventDic[eventName];
                if (d == null)
                {
                    throw new Exception(string.Format("移除监听错误:事件{0}没有对应的委托", eventName));
                }
                else if (d.GetType() != callBack.GetType())
                {
                    throw new Exception(string.Format("移除监听错误:尝试为事件{0}移除不同类型的委托,当前委托类型为{1},要移除的委托类型为{2}", eventName, d.GetType(), callBack.GetType()));
                }
            }
            else
            {
                throw new Exception(string.Format("移除监听错误:没有事件码{0}", eventName));
            }
        }

        private static void Remove(string eventName)
        {
            if (m_EventDic[eventName] == null)
            {
                m_EventDic.Remove(eventName);
            }
        }

    }
}
### Unity 中的事件监听机制及其实现方式 #### 1. **事件监听机制的核心概念** 事件监听机制是一种基于观察者模式的设计方法,用于实现模块间的低耦合通信。在 Unity 开发中,这种机制通常通过 C#委托 (Delegate) 和事件 (Event) 来实现[^2]。 - 委托是一个指向函数的对象,它可以存储对特定方法的引用。 - 事件则是基于委托的一种特殊用途,允许对象通知其他对象发生了某些事情。 #### 2. **基本实现原理** 事件中心框架的主要功能是让不同的模块能够订阅和发布事件。以下是其核心流程: - **注册 (Subscribe)**:感兴趣的模块向事件中心注册自己想要监听的事件类型。 - **取消注册 (Unsubscribe)**:当不再需要接收某类事件时,模块可以从事件中心注销。 - **广播 (Publish)**:某一模块触发了一个事件事件中心会将此事件传递给所有已注册的相关模块。 #### 3. **具体实现代码** ##### (1)创建事件管理器 事件管理器负责管理和调度所有的事件订阅发布操作。以下是一个简单的 `EventManager` 类实现示例: ```csharp using System; using System.Collections.Generic; public class EventManager : MonoBehaviour { private static Dictionary<string, Action<object>> eventDictionary = new Dictionary<string, Action<object>>(); // 添加事件监听 public static void Subscribe(string eventName, Action<object> listener) { if (!eventDictionary.ContainsKey(eventName)) eventDictionary.Add(eventName, null); eventDictionary[eventName] += listener; } // 移除事件监听 public static void Unsubscribe(string eventName, Action<object> listener) { if (eventDictionary.TryGetValue(eventName, out var currentListener)) { currentListener -= listener; if (currentListener == null) eventDictionary.Remove(eventName); else eventDictionary[eventName] = currentListener; } } // 发布事件 public static void Publish(string eventName, object data = null) { if (eventDictionary.TryGetValue(eventName, out var listeners)) { listeners?.Invoke(data); } } } ``` ##### (2)使用事件管理器 下面是如何使用上述 `EventManager` 进行事件的订阅、取消订阅以及发布的例子: ```csharp // 订阅事件 void OnEnable() { EventManager.Subscribe("PlayerDied", HandlePlayerDied); } // 取消订阅事件 void OnDisable() { EventManager.Unsubscribe("PlayerDied", HandlePlayerDied); } // 处理事件的方法 private void HandlePlayerDied(object data) { Debug.Log($"Player died with score: {data}"); } // 广播事件 public void KillPlayer(int score) { EventManager.Publish("PlayerDied", score); } ``` #### 4. **优化建议** 为了提高性能并减少内存消耗,可以引入可回收事件类的概念。例如,在 MotionFramework 中提到的 IReference 接口可以帮助我们在事件广播完成后自动释放资源[^3]。 另外,为了避免字符串硬编码带来的错误风险,推荐使用枚举作为事件名称。如下所示: ```csharp public enum EventType { PlayerDied, MonsterDead, GameOver } // 修改后的订阅接口 public static void Subscribe(EventType eventType, Action<object> listener) { string eventName = Enum.GetName(typeof(EventType), eventType); Subscribe(eventName, listener); } // 调用更安全的方式 EventManager.Subscribe(EventType.PlayerDied, HandlePlayerDied); ``` #### 5. **优势分析** - **降低耦合性**:各模块无需直接调用对方的方法即可完成交互。 - **增强扩展性**:新增功能只需简单添加新的事件处理逻辑而不会影响现有架构。 - **简化维护工作量**:清晰的责任划分使得后续修改更加便捷高效[^4]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值