事件提供了一種標准的機制來通知監聽者。.NET的事件模式使用了事件語法來實現觀察者模式。任意數量的客戶對象都可以將自己的處理函數注冊到事件上,然后處理這些事件。這些客戶對象不需要再編譯期就給出。時間也不必非要有訂閱者才能正常工作。在C#中使用事件可以降低發送者和可能的通知接受者之間的耦合。發送者可以完全獨立於接收者進行開發。事件是實現廣播類型行為信息的標准方式。 下面按照使用場景的不同,簡單列舉三種事件模式的實現方式: 0. 公共代碼部分 1 /// <summary> 復制代碼 2 /// 日志參數類 3 /// </summary> 4 public class LoggerEventArgs : EventArgs 5 { 6 public string Message { get; private set; } 7 public int Priority { get; private set; } 8 9 public LoggerEventArgs(int p, string m) 10 { 11 Priority = p; 12 Message = m; 13 } 14 } 復制代碼 1. 最常用方式 1 /// <summary> 復制代碼 2 /// 日志類(第一版):最常見的使用方法,適用於單一調用者情況。 3 /// </summary> 4 public class Logger 5 { 6 /// <summary> 7 /// 內部事件句柄 8 /// </summary> 9 public event EventHandler<LoggerEventArgs> Log; 10 /// <summary> 11 /// 內部日志單鍵實例 12 /// </summary> 13 private static Logger theOnly = null; 14 public static Logger Singleton 15 { 16 get { return theOnly; } 17 } 18 19 private Logger() 20 { } 21 22 static Logger() 23 { 24 theOnly = new Logger(); 25 } 26 27 /// <summary> 28 /// 添加日志信息 29 /// </summary> 30 /// <param name="priority"></param> 31 /// <param name="msg"></param> 32 public void AddMsg(int priority, string msg) 33 { 34 // 該臨時變量可預防多線程環境中的競爭條件 35 EventHandler<LoggerEventArgs> l = Log; 36 // 執行事件方法 37 if (l != null) 38 { 39 l(this, new LoggerEventArgs(priority, msg)); 40 } 41 } 42 } 復制代碼 2. 針對事件數量多的情況 1 /// <summary> 復制代碼 2 /// 日志類(第二版):適用於包含事件數量非常多的情況,即添加了一個事件容器,避免因多事件導致的設計臃腫。 3 /// </summary> 4 public sealed class Logger 5 { 6 /// <summary> 7 /// 事件容器 8 /// </summary> 9 private static System.ComponentModel.EventHandlerList Handlers = new System.ComponentModel.EventHandlerList(); 10 11 /// <summary> 12 /// 添加事件 13 /// </summary> 14 /// <param name="system"></param> 15 /// <param name="ev"></param> 16 public static void AddLogger(string system, EventHandler<LoggerEventArgs> ev) 17 { 18 Handlers.AddHandler(system, ev); 19 } 20 21 /// <summary> 22 /// 清除事件 23 /// </summary> 24 /// <param name="system"></param> 25 /// <param name="ev"></param> 26 public static void RemoveLogger(string system, EventHandler<LoggerEventArgs> ev) 27 { 28 Handlers.RemoveHandler(system, ev); 29 } 30 31 /// <summary> 32 /// 添加日志信息 33 /// </summary> 34 /// <param name="system"></param> 35 /// <param name="priority"></param> 36 /// <param name="msg"></param> 37 public static void AddMsg(string system, int priority, string msg) 38 { 39 if (!string.IsNullOrEmpty(system)) 40 { 41 // 根據key獲取相應的事件 42 EventHandler<LoggerEventArgs> l = Handlers[system] as EventHandler<LoggerEventArgs>; 43 // 事件參數 44 LoggerEventArgs args = new LoggerEventArgs(priority, msg); 45 if (l != null) 46 { 47 l(null, args); 48 } 49 // 若不存在,執行默認事件 50 l = Handlers[""] as EventHandler<LoggerEventArgs>; 51 if (l != null) 52 { 53 l(null, args); 54 } 55 } 56 } 57 } 復制代碼 3. 針對事件數量多的情況(泛型版本) 1 /// <summary> 復制代碼 2 /// 日志類(第三版):適用於多事件情況的泛型版本。主要優勢是降低了轉型/轉換的工作,但增加了一些用來映射事件的代碼。 3 /// </summary> 4 public sealed class Logger 5 { 6 /// <summary> 7 /// 事件字典 8 /// </summary> 9 private static Dictionary<string, EventHandler<LoggerEventArgs>> Handlers = new Dictionary<string, EventHandler<LoggerEventArgs>>(); 10 11 /// <summary> 12 /// 添加事件 13 /// </summary> 14 /// <param name="system"></param> 15 /// <param name="ev"></param> 16 static public void AddLogger(string system, EventHandler<LoggerEventArgs> ev) 17 { 18 if (Handlers.ContainsKey(system)) 19 { 20 Handlers[system] += ev; 21 } 22 else 23 { 24 Handlers.Add(system, ev); 25 } 26 } 27 28 /// <summary> 29 /// 清除事件 30 /// </summary> 31 /// <param name="system"></param> 32 /// <param name="ev"></param> 33 static public void RemoveLogger(string system, EventHandler<LoggerEventArgs> ev) 34 { 35 Handlers[system] -= ev; 36 } 37 38 /// <summary> 39 /// 添加日志信息 40 /// </summary> 41 /// <param name="system"></param> 42 /// <param name="priority"></param> 43 /// <param name="msg"></param> 44 static public void AddMsg(string system, int priority, string msg) 45 { 46 if (string.IsNullOrEmpty(system)) 47 { 48 // 從字典中獲取事件 49 EventHandler<LoggerEventArgs> l = null; 50 Handlers.TryGetValue(system, out l); 51 // 事件參數 52 LoggerEventArgs args = new LoggerEventArgs(priority, msg); 53 // 執行事件 54 if (l != null) 55 { 56 l(null, args); 57 } 58 // 若不存在,則嘗試執行默認事件 59 l = Handlers[""] as EventHandler<LoggerEventArgs>; 60 if (l != null) 61 { 62 l(null, args); 63 } 64 } 65 } 66 } 復制代碼 至於選擇哪種方式來實現,就要看具體的應用場景了;此外,大多數時候我們都會使用匿名委托來聲明回調函數,或事件委托,所以會導致代碼的運行時態有一些小波折,尤其在讀別人的代碼的時候,這樣的情況很普遍,會不會有更好的辦法來讓這種回調和委托比較容易跟蹤?這個還在思考中……
