前面設實現了事件系統,現在開始實現事件.我們先抽象一個事件基類.先上代碼.
/// <summary> /// 事件方法 /// </summary> public abstract class EventMethod { #region Field /// <summary> /// 事件句柄 /// </summary> private string handle; #endregion #region Property /// <summary> /// 事件句柄 /// </summary> public string Handle { get => handle; } #endregion #region Construction /// <summary> /// 創建一個 EventMethod 類新實例 /// </summary> public EventMethod() => handle = GetHandle(); #endregion #region Method /// <summary> /// 獲取綁定的事件句柄 /// </summary> protected virtual string GetHandle() => GetType().Name; /// <summary> /// 喚醒事件 /// </summary> internal abstract void Awake(params object[] parameters); #endregion }
事件句柄就是代表了這個委托關注的哪個事件.Awake方法就是執行委托,因為事件的參數我們現在不能確定,所以這里Awake參數是params的.其他具體的事件通過重寫Awake來進行重新重構.下面就重構一個簡單按鈕單擊事件作為例子.
/// <summary> /// 按鈕單擊事件 /// </summary> public class BtnClick : EventMethod { #region Field /// <summary> /// 回調委托 /// </summary> private Action action; #endregion #region Construction /// <summary> /// 創建一個 BtnClick 類新實例 /// </summary> public BtnClick(Action action) => this.action = action; #endregion #region Method /// <summary> /// 喚醒事件 /// </summary> /// <param name="parameters"></param> internal override void Awake(params object[] parameters) => action?.Invoke(); #endregion }
以上,我們就完成了一個事件的設計.然后補齊事件系統的觸發.
/// <summary> /// 事件系統 /// </summary> public class EventSystem { #region Field /// <summary> /// 事件容器 /// </summary> private readonly Dictionary<string, HashSet<EventMethod>> events = new Dictionary<string, HashSet<EventMethod>>();
#endregion #region Method /// <summary> /// 添加事件 /// </summary> /// <param name="eventMethod"></param> public bool Add(EventMethod eventMethod) { //事件方法集合,可能在剛判斷存在,但是在另外一個線程中同時被刪除.所以這里重試5次 for (int i = 0; i < 5; i++) { //創建時間方法集合 if (!events.ContainsKey(eventMethod.Handle)) { lock (events) { if (!events.ContainsKey(eventMethod.Handle)) events.Add(eventMethod.Handle, new HashSet<EventMethod>()); } } if (events.TryGetValue(eventMethod.Handle, out var hashSet)) { lock (hashSet) { return hashSet.Add(eventMethod); } } } return false; //throw new Exception($"添加事件{eventMethod.Handle}失敗!"); } /// <summary> /// 移除事件 /// </summary> /// <param name="eventMethod"></param> public void Remove(EventMethod eventMethod) { if (events.TryGetValue(eventMethod.Handle, out var hashSet)) { lock (hashSet) { hashSet.Remove(eventMethod); //移除已經空置的事件方法集合 if (hashSet.Count <= 0) events.Remove(eventMethod.Handle); } } } /// <summary> /// 喚醒事件 /// </summary> /// <param name="handle"></param> /// <param name="parameters"></param> public void Awake(string handle, params object[] parameters) { if (events.TryGetValue(handle, out var value)) { lock (value) { foreach (var item in value) item.Awake(parameters); } } } #endregion }
通過Add/Rmove添加或移除一個委托.通過Awake方法獲取一個委托集合,然后依次調用來實現觸發這個事件.
測試代碼如下
static void Main(string[] args) { BtnClick btnClick = new BtnClick(() =>Console.WriteLine("按鈕被單擊")); EventSystem eventSystem = new EventSystem(); eventSystem.Add(btnClick); eventSystem.Awake("BtnClick"); Console.ReadLine(); }
以上,我們就實現了一個簡單的事件系統.當然還有很多的可擴展部分,大家根據自己的需求調整擴展即可.
傳送門: