事件提供了一种标准的机制来通知监听者。.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 } 复制代码 至于选择哪种方式来实现,就要看具体的应用场景了;此外,大多数时候我们都会使用匿名委托来声明回调函数,或事件委托,所以会导致代码的运行时态有一些小波折,尤其在读别人的代码的时候,这样的情况很普遍,会不会有更好的办法来让这种回调和委托比较容易跟踪?这个还在思考中……