EventBus EventBus 用於維護一個事件源與事件處理的映射字典 通過 Singleton,確保 EventBus 的唯一入口 利用反射完成事件源與件事處理的初始化綁定 提供統一的事件注冊(register)、取消注冊(unsubscribe)和觸發(trigger)。 Interfaces IEventData public interface IEventData { DateTime EventTime { get; set; } object EventSource {get; set; } } IEventHandler public interface IEventHandler { } IEventHandler`1 public interface IEventHandler<TEventData> : IEventHandler where TEventData : IEventData { void HandlerEvent(TEventData eventData); } base class EventData public class EventData : IEventData { public DateTime EventTIme { get; set; } object EventSource { get; set; } public EventData() { EventTime = DateTime.Now; } } Domain FishType public enum FishType { None, 鯽魚, 鯉魚, 黑魚, 青魚, 草魚, 鱸魚 } FishingEventData : EventData public class FishingEventData : EventData { public FishType FishType { get; set; } public FishingMan FishingMan { get; set; } } FishingEventHandler : IEventHandler public class FishingEventHandler : IEventHandler<FishingEventData> { public void HandleEvent(FishingEventData eventData) { var type = eventData.FishType; var fishMan = eventData.FishingMan; var Name = fishMan.Name; if (type == FishType.None) { fishMan.Message = string.Format("{0}: 沒有釣到魚, 累計釣了{1}條魚", Name, fishMan.FishCount); } else { fishMan.FishCount++; fishMan.Message = string.Format("{0}: 釣到一條[{2}], 累計釣了{1}條魚", Name, fishMan.FishCount, type); } } } FishingMan public class FishingMan { public string Name { get; set; } public int FishCount { get; set; } public FishingRod FishingRod { get; set; } public string Message { get; set; } public FishingMan(string name) { Name = name; FishCount = 0; } public void Fishing() { FishingRod.ThrowHook(this); } } FishingRod 用反射註冊事件 public class FishingRod { public string Message { get; private set; } public FishingRod() { } public void ThrowHook(FishingMan man) { if (new Random().Next() % 2 == 0) { var type = (FishType)(new Random().Next(0, 5) + 1); Message = ("魚兒上鉤了!"); if (FishingEvent != null) { var eventData = new FishingEventData { FishingMan = man, FishType = type }; EventBus.Default.Trigger<FishingEventData>(eventData); } } else { var type = FishType.None; Message = ("可惜了!"); if (FishingEvent != null) { var eventData = new FishingEventData { FishingMan = man, FishType = type }; EventBus.Default.Trigger<FishingEventData>(eventData); } } } } EventBus 實作 用一個靜態單例來統一管理事件 public class EventBus { public static EventBus Default => new EventBus(); private readonly ConcurrentDictionary<Type, List<Type>> _eventAndHandlerMapping; private EventBus() { _eventAndHandlerMapping = new ConcurrentDictionary<Type, List<Type>>(); MapEventToHandler(); } private void MapEventToHandler() { Assembly assembly = Assembly.GetEntryAssembly(); foreach (var type in assembly.GetTypes()) { if (typeof(IEventHandler).IsAssignableFrom(type)) { Type handlerInterface = type.GetInterface("IEventHandler`1"); if (handlerInterface == null) continue; Type eventDataType = handlerInterface.GetGenericArguments()[0]; if (_eventAndHandlerMapping.ContainsKey(eventDataType)) { List<Type> handlerTypes = _eventAndHandlerMapping[eventDataType]; handlerTypes.Add(type); _eventAndHandlerMapping[eventDataType] = handlerTypes; } else { var handlerTypes = new List<Type> { type }; _eventAndHandlerMapping[eventDataType] = handlerTypes; } } } } public void Register<TEventData>(Type eventHandler) { List<Type> handlerTypes = _eventAndHandlerMapping[typeof(TEventData)]; if (!handlerTypes.Contains(eventHandler)) { handlerTypes.Add(eventHandler); _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes; } } public void Unsubscribe<TEventData>(Type eventHandler) { List<Type> handlerTypes = _eventAndHandlerMapping[typeof(TEventData)]; if (!handlerTypes.Contains(eventHandler)) { handlerTypes.Remove(eventHandler); _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes; } } public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData { List<Type> handlers = _eventAndHandlerMapping[eventData.GetType()]; if (handlers != null && handlers.Count > 0) { foreach (var handler in handlers) { MethodInfo methodInfo = handler.GetMethod("HandleEvent"); if (methodInfo != null) { object obj = Activator.CreateInstance(handler); methodInfo.Invoke(obj, new object[] { eventData }); } } } } } demo MacOs Cocoa Project public partial class ViewController : NSViewController { public ViewController (IntPtr handle) : base (handle) { } public override void ViewDidLoad () { base.ViewDidLoad (); jeff = new FishingMan("Jeff"); rod = new FishingRod(); jeff.FishingRod = rod; EventBus eventBus = EventBus.Default; eventBus.Register<FishingEventData>(typeof(FishingEventHandler)); } FishingMan jeff; FishingRod rod; public override NSObject RepresentedObject { get { return base.RepresentedObject; } set { base.RepresentedObject = value; } } partial void Button_Click(NSButton sender) { jeff.Fishing(); TextLabel.StringValue = rod.Message; TextLabel2.StringValue = jeff.Message ?? ""; } }