委托回调是项目中消息床传递用得最多的。u3d中虽然有sendmessage方法。但远远没有委托发送消息好。当然。这里不仅仅是用于u3d中
先来看一个全局的消息处理类eventd.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace eventd 8 { 9 /// 消息码定义(最好定义到各个服务自己的头文件中) 10 public enum Evt 11 { 12 Invalid = 0, /// 无效事件 13 14 // 状态事件// 15 ConnectStateChanged, /// 连接状态改变// 16 Disconnection, /// 连接断开// 17 //其他状态 18 Max 19 } 20 21 /// <summary> 22 /// 需要传递事件数据的类 23 /// </summary> 24 public class EventArgs_Animal : EventArgs 25 { 26 public int type; 27 public string name; 28 } 29 }
全局消息定义
然后一个事件系统。用于发布事件和订阅消息EventSystem.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace eventd 8 { 9 10 class EventKey 11 { 12 public ushort eventId = 0; // event id 13 public uint uniqueKey = 0; // event source id 14 } 15 16 class EventKeyEqualityComparer : IEqualityComparer<EventKey> 17 { 18 public bool Equals(EventKey k1, EventKey k2) 19 { 20 return (k1.eventId == k2.eventId && k1.uniqueKey == k2.uniqueKey); 21 } 22 23 public int GetHashCode(EventKey ek) 24 { 25 int hCode = (int)((uint)((ek.uniqueKey & 0xFFFF) << 16) + (uint)ek.eventId); 26 //int hCode = ek.uniqueKey ^ (uint)ek.eventId; 27 return hCode.GetHashCode(); 28 } 29 } 30 31 public delegate void EventHandler(ushort eventId, uint uniqueKey, EventArgs args); 32 33 34 /// 事件订阅信息 35 class SubscribeInfo 36 { 37 public event EventHandler eventHandler = null; 38 public int callCount = 0; 39 40 public void Attach(EventHandler eventHandler) 41 { 42 this.eventHandler += eventHandler; 43 } 44 45 public void Detach(EventHandler eventHandler) 46 { 47 this.eventHandler -= eventHandler; 48 } 49 50 public void Emit(ushort eventId, uint uniqueKey, EventArgs args) 51 { 52 if (eventHandler != null) 53 { 54 callCount++; 55 56 // 加入异常捕捉,防止异常后导致callCount不递减,从而引发不真实的错误 57 try 58 { 59 this.eventHandler(eventId, uniqueKey, args); 60 } 61 catch (Exception e) 62 { 63 //Log.Trace("Event callback exception, EventId: " + eventId); 64 //Debug.LogException(e); 65 } 66 67 callCount--; 68 } 69 } 70 71 public bool CanRemove() 72 { 73 return (eventHandler == null); 74 } 75 } 76 77 public class EventSystem 78 { 79 private Dictionary<EventKey, SubscribeInfo> mEventHandlerMap = null; 80 private int mEmitDepth = 0; 81 private const int MAX_EMIT_DEPTH = 20; 82 private int[] mEventIdStack = new int[MAX_EMIT_DEPTH]; 83 84 //public static readonly EventSystem Instance = new EventSystem(); 85 private static EventSystem sInstance = null; 86 public static EventSystem Instance 87 { 88 get 89 { 90 if (sInstance == null) 91 sInstance = new EventSystem(); 92 return sInstance; 93 } 94 } 95 96 private EventSystem() 97 { 98 EventKeyEqualityComparer comp = new EventKeyEqualityComparer(); 99 mEventHandlerMap = new Dictionary<EventKey, SubscribeInfo>(comp); 100 } 101 102 /// <summary> 103 /// 注册事件 104 /// </summary> 105 /// <param name="handler">方法名</param> 106 /// <param name="eventId"></param> 107 /// <param name="uniqueKey"></param> 108 /// <returns></returns> 109 public bool AddListener(EventHandler handler, ushort eventId, uint uniqueKey) 110 { 111 if (handler == null) 112 return false; 113 114 EventKey ek = new EventKey(); 115 ek.eventId = eventId; 116 ek.uniqueKey = uniqueKey; 117 118 if (mEventHandlerMap.ContainsKey(ek)) 119 { 120 SubscribeInfo si = mEventHandlerMap[ek]; 121 si.Attach(handler); 122 } 123 else 124 { 125 SubscribeInfo si = new SubscribeInfo(); 126 si.Attach(handler); 127 128 mEventHandlerMap.Add(ek, si); 129 } 130 131 return true; 132 } 133 134 public void RemoveListener(EventHandler handler, ushort eventId, uint uniqueKey) 135 { 136 if (handler == null) 137 return; 138 139 EventKey ek = new EventKey(); 140 ek.eventId = eventId; 141 ek.uniqueKey = uniqueKey; 142 143 if (mEventHandlerMap.ContainsKey(ek)) 144 { 145 SubscribeInfo si = mEventHandlerMap[ek]; 146 si.Detach(handler); 147 } 148 } 149 150 151 public void Emit(ushort eventId, uint uniqueKey, EventArgs args) 152 { 153 EventKey ek = new EventKey(); 154 ek.eventId = eventId; 155 156 // 先发送有源指针的 157 ek.uniqueKey = uniqueKey; 158 if (ek.uniqueKey != 0) 159 { 160 _Emit(ek, eventId, uniqueKey, args); 161 } 162 163 // 然后发送没有源指针的 164 ek.uniqueKey = 0; 165 _Emit(ek, eventId, uniqueKey, args); 166 } 167 168 169 private bool _Emit(EventKey ek, ushort eventId, uint uniqueKey, EventArgs args) 170 { 171 mEmitDepth++; 172 173 if (mEmitDepth > 0 && mEmitDepth <= MAX_EMIT_DEPTH) 174 mEventIdStack[mEmitDepth - 1] = eventId; 175 if (mEmitDepth >= MAX_EMIT_DEPTH) 176 { 177 //Console.WriteLine("Event engine error, endless loop, EventID: " + eventId); 178 179 printCallstack(); 180 181 mEmitDepth--; 182 183 return false; 184 } 185 186 if (mEventHandlerMap.ContainsKey(ek)) 187 { 188 SubscribeInfo si = mEventHandlerMap[ek]; 189 190 if (si.callCount >= 5) 191 { 192 //Console.WriteLine("Fatal error, an event is endless loop, EventID: " + eventId); 193 194 printCallstack(); 195 196 mEmitDepth--; 197 198 return false; 199 } 200 201 202 if (si.CanRemove()) 203 { 204 mEventHandlerMap.Remove(ek); 205 } 206 else 207 { 208 si.Emit(eventId, uniqueKey, args); 209 } 210 } 211 212 mEmitDepth--; 213 214 return true; 215 } 216 217 private void printCallstack() 218 { 219 string osb = ""; 220 for (int i = 0; i < mEmitDepth; i++) 221 { 222 osb += mEventIdStack[i] + ","; 223 } 224 //Console.WriteLine("Event callstack: " + osb); 225 } 226 227 } 228 }
事件系统
模拟:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace eventd 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 Program p = new Program(); 14 p.AddEvents(); //注册事件 15 16 string str = Console.ReadLine(); 17 18 //模拟断开连接 19 if (str == "1") 20 { 21 //消息,跟根据自己需要 22 EventArgs_Animal animal = new EventArgs_Animal(); 23 animal.type = 20; 24 animal.name = "姓名"; 25 26 //无事件数据 27 //EventSystem.Instance.Emit((ushort)Evt.ConnectStateChanged, 0, null); 28 29 //有事件数据 30 //连接断开。触发事件 31 EventSystem.Instance.Emit((ushort)Evt.ConnectStateChanged, 0, animal); 32 } 33 34 Console.ReadLine(); 35 } 36 37 public void AddEvents() 38 { 39 //EventSystem.Instance.AddListener(OnUpdateChatMessage, (ushort)Evt.UpdateChatMessage, 0); 40 41 //注册事件。当ConnectStateChanged 即断开连接时候触发 42 EventSystem.Instance.AddListener(onUpdate, (ushort)Evt.ConnectStateChanged, 0); 43 } 44 //public override void RemoveEvents() 45 /// <summary> 46 /// 移除事件 47 /// </summary> 48 public void RemoveEvents() 49 { 50 // base.RemoveEvents(); 51 52 EventSystem.Instance.RemoveListener(onUpdate, (ushort)Evt.ConnectStateChanged, 0); 53 } 54 // public delegate void EventHandler(ushort eventId, uint uniqueKey, EventArgs args); 55 void onUpdate(ushort eventId, uint uniqueKey, EventArgs args) 56 { 57 EventArgs_Animal a = args as EventArgs_Animal; 58 59 if (a != null) 60 { 61 Console.WriteLine(a.name); 62 Console.WriteLine(a.type); 63 } 64 Console.WriteLine("回调"); 65 } 66 } 67 }
看完之后你不是会问。这有什么意义啊。
用这句
EventSystem.Instance.Emit((ushort)Evt.ConnectStateChanged, 0, animal);
直接代替onUpdate()方法不就可以了吗?写这么多好麻烦?
这里只是演示。触发订阅者的方法的代码。不一定非得跟方法在一个类。
就拿我这个演示的来说。我在A类注册了事件。那就很显示onUpdate方法在A类中
可以在B类触发。也就是在B类执行代码
EventSystem.Instance.Emit((ushort)Evt.ConnectStateChanged, 0, animal);
时间: 2024-10-07 12:04:04