Yu Chenhaoran's Portfolio Help

事件分发中心代码

事件分发中心在项目构架中扮演着重要的角色,原因如下:

  • 解耦合 : 允许不同模块间进行通信,且不需要知道订阅者或发布者的具体逻辑,从而减少依赖关系

  • 增强可拓展性 : 只需要增加或移除事件的侦听器即可实现订阅者的增减,无需考虑事件的来源/其他接收

  • 异步处理 : 促进事件异步处理,从而提高性能

  • 易于测试 : 所有对事件响应的代码模块可进行单独测试,只需要模拟事件的触发即可

以下是一个个人项目中的代码实现:

#region Editor // --------------------------------- // Class : EventDispatcher // Creator : Electric Arc( Yu chenhaoran) // Co-Workers : None // Create Date : 2024/04/29 // File Version : v 1.0.0 // --------------------------------- #endregion using System; using System.Collections.Generic; namespace Framework.Services.EventDispatcherService { /// <summary> /// The EventDispatcher class is a singleton that manages event subscription, unsubscription, and dispatching. /// </summary> public sealed class EventDispatcher: Service<EventDispatcher>, IService { #region Delegates do not return a value // Dictionary to store event handlers private readonly Dictionary<string, Dictionary<string, Delegate>> _eventTypeDictionary = new(); #region Delegate without parameter passing /// <summary> /// Subscribes a handler to an event. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe(string eventType, string eventName, Action handler) { AddHandler(eventType, eventName, handler); } /// <summary> /// Unsubscribes a handler from an event. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe(string eventType, string eventName, Action handler) { RemoveHandler(eventType, eventName, handler); } /// <summary> /// Dispatches an event. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> public void Dispatch(string eventType, string eventName) { if (_eventTypeDictionary.ContainsKey(eventType)) if (_eventTypeDictionary[eventType].TryGetValue(eventName, out var action)) ((Action)action)?.Invoke(); } #endregion #region Delegate with parameter passing /// <summary> /// Subscribes a handler to an event with a parameter. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe<T>(string eventType, string eventName, Action<T> handler) { AddHandler(eventType, eventName, handler); } /// <summary> /// Unsubscribes a handler from an event with a parameter. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe<T>(string eventType, string eventName, Action<T> handler) { RemoveHandler(eventType, eventName, handler); } /// <summary> /// Dispatches an event with a parameter. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="eventParam">The parameter for the event.</param> public void Dispatch<T>(string eventType, string eventName, T eventParam) { if (_eventTypeDictionary.ContainsKey(eventType)) if (_eventTypeDictionary[eventType].TryGetValue(eventName, out var action)) ((Action<T>)action)?.Invoke(eventParam); } #endregion #region Delegate with multiple parameter passing /// <summary> /// Subscribes a handler to an event with multiple parameters. /// </summary> /// <example> /// <code> /// EventDispatcher.Instance.Subscribe("TestEvent", "OnTest", (params) => /// { /// //Handle the event /// }); /// </code> /// </example> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe(string eventType, string eventName, Action<object[]> handler) { AddHandler(eventType, eventName, handler); } /// <summary> /// Unsubscribes a handler from an event with multiple parameters. /// </summary> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe(string eventType, string eventName, Action<object[]> handler) { RemoveHandler(eventType, eventName, handler); } /// <summary> /// Dispatches an event with multiple parameters. /// </summary> /// <example> /// <code> /// EventDispatcher.Instance.Dispatch("TestEvent", "OnTest", param1, param2, param3, ..., paramN); /// </code> /// </example> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="eventParams">The parameters for the event.</param> public void Dispatch(string eventType, string eventName, params object[] eventParams) { if (_eventTypeDictionary.ContainsKey(eventType)) if (_eventTypeDictionary[eventType].TryGetValue(eventName, out var action)) ((Action<object[]>)action)?.Invoke(eventParams); } #endregion #region Handler private void AddHandler(string eventType, string eventName, Delegate handler) { if (!_eventTypeDictionary.ContainsKey(eventType)) _eventTypeDictionary.Add(eventType, new Dictionary<string, Delegate>()); var eventDictionary = _eventTypeDictionary[eventType]; if (!eventDictionary.ContainsKey(eventName)) eventDictionary.Add(eventName, null); eventDictionary[eventName] = Delegate.Combine(eventDictionary[eventName], handler); } private void RemoveHandler(string eventType, string eventName, Delegate handler) { if (_eventTypeDictionary.ContainsKey(eventType) && _eventTypeDictionary[eventType].ContainsKey(eventName)) { var eventDictionary = _eventTypeDictionary[eventType]; eventDictionary[eventName] = Delegate.Remove(eventDictionary[eventName], handler); // If there are no more events of this type, remove the event type if (eventDictionary[eventName] == null) { eventDictionary.Remove(eventName); if (eventDictionary.Count == 0) _eventTypeDictionary.Remove(eventType); } } } #endregion #endregion #region Delegates returning a value // Dictionary to store event handlers that return a value private readonly Dictionary<string, Dictionary<string, Delegate>> _returningEventTypeDictionary = new(); #region Delegates returning a value and with parameter passing /// <summary> /// Subscribes a handler to an event that returns a value. /// </summary> /// <typeparam name="T">The type of the event parameter.</typeparam> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe<T, TResult>(string eventType, string eventName, Func<T, TResult> handler) { AddHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Unsubscribes a handler from an event that returns a value. /// </summary> /// <typeparam name="T">The type of the event parameter.</typeparam> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe<T, TResult>(string eventType, string eventName, Func<T, TResult> handler) { RemoveHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Dispatches an event that returns a value. /// </summary> /// <typeparam name="T">The type of the event parameter.</typeparam> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="eventParam">The parameter for the event.</param> /// <returns>The result of the event handler.</returns> public TResult Dispatch<T, TResult>(string eventType, string eventName, T eventParam) { if (_returningEventTypeDictionary.ContainsKey(eventType)) if (_returningEventTypeDictionary[eventType].TryGetValue(eventName, out var action)) return ((Func<T, TResult>)action).Invoke(eventParam); return default; } #endregion #region Delegates returning a value and with multiple parameter passing /// <summary> /// Subscribes a handler to an event that returns a value with multiple parameters. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe<TResult>(string eventType, string eventName, Func<object[], TResult> handler) { AddHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Unsubscribes a handler from an event that returns a value with multiple parameters. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe<TResult>(string eventType, string eventName, Func<object[], TResult> handler) { RemoveHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Dispatches an event that returns a value with multiple parameters. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="eventParams">The parameters for the event.</param> /// <returns>The result of the event handler.</returns> public TResult Dispatch<TResult>(string eventType, string eventName, params object[] eventParams) { if (_returningEventTypeDictionary.ContainsKey(eventType)) if (_returningEventTypeDictionary[eventType].TryGetValue(eventName, out var action)) return ((Func<object[], TResult>)action).Invoke(eventParams); return default; } #endregion #region Delegates returning a value and without parameter passing /// <summary> /// Subscribes a handler to an event that returns a value without parameter passing. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Subscribe<TResult>(string eventType, string eventName, Func<TResult> handler) { AddHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Unsubscribes a handler from an event that returns a value without parameter passing. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <param name="handler">The handler for the event.</param> public void Unsubscribe<TResult>(string eventType, string eventName, Func<TResult> handler) { RemoveHandler(eventType, eventName, handler, _returningEventTypeDictionary); } /// <summary> /// Dispatches an event that returns a value without parameter passing. /// </summary> /// <typeparam name="TResult">The type of the return value.</typeparam> /// <param name="eventType">The type of the event.</param> /// <param name="eventName">The name of the event.</param> /// <returns>The result of the event handler.</returns> public TResult Dispatch<TResult>(string eventType, string eventName) { if (_returningEventTypeDictionary.ContainsKey(eventType)) if (_returningEventTypeDictionary[eventType].TryGetValue(eventName, out var action)) return ((Func<TResult>)action).Invoke(); return default; } #endregion #region Handler private void AddHandler(string eventType, string eventName, Delegate handler, Dictionary<string, Dictionary<string, Delegate>> eventTypeDictionary) { if (!eventTypeDictionary.ContainsKey(eventType)) eventTypeDictionary.Add(eventType, new Dictionary<string, Delegate>()); var eventDictionary = eventTypeDictionary[eventType]; if (!eventDictionary.ContainsKey(eventName)) eventDictionary.Add(eventName, null); eventDictionary[eventName] = Delegate.Combine(eventDictionary[eventName], handler); } private void RemoveHandler(string eventType, string eventName, Delegate handler, Dictionary<string, Dictionary<string, Delegate>> eventTypeDictionary) { if (eventTypeDictionary.ContainsKey(eventType) && eventTypeDictionary[eventType].ContainsKey(eventName)) { var eventDictionary = eventTypeDictionary[eventType]; eventDictionary[eventName] = Delegate.Remove(eventDictionary[eventName], handler); // If there are no more events of this type, remove the event type if (eventDictionary[eventName] == null) { eventDictionary.Remove(eventName); if (eventDictionary.Count == 0) eventTypeDictionary.Remove(eventType); } } } #endregion #endregion } }

同时为了方便名称的管理,创建了一个常量集,用以存储事件的名称,以下为部分示例:

namespace Const { public static class EventTypeAndNameLib { public static readonly string GameFlowEvents = "GameFlowEvents"; #region GameFlowEvents public static readonly string OnPlayerJoin = "OnPlayerJoin"; public static readonly string OnPlayerLeave = "OnPlayerLeave"; public static readonly string OnGameStart = "OnGameStart"; public static readonly string GetAllPlayerID = "GetAllPlayerID"; #endregion } }
Last modified: 13 April 2025