C#基础:事件(四)

事件定义的时候,可以使用add和remove关键字来自定义事件处理函数的添加与移除功能。例如,可以在添加和移除之前,使用lock关键字实现线程同步。虽然MethodImplAttribute会用当前类的对象作为同步对象实现线程同步,但当对象需要向外界公布多个事件的时候,这样做会产生效率问题。比如:对象A向外界公布了E1、E2两个事件,订阅方O1使用+=运算符试图订阅E1事件;订阅方O2也使用+=运算符试图订阅E2事件。假设这两个订阅操作同时进行,那么无论谁先抢到订阅权,另一个操作不得不等待,直到前一个订阅操作成功完成。这是因为,MethodImplAttribute会将A用作线程同步的锁定对象;对于O1和O2而言,在订阅事件的时候,是共用同一个锁定对象的。MethodImplAttribute另一个问题在于,如果A是一个值对象,那么就根本没法使用A作为锁定对象,因为A根本没有“同步索引”,因此你就无法使用多线程去同步使用这样的对象,即使是使用了MethodImplAttribute,也只不过是一个摆设。

仍然以EventDemo项目为例,我们将该案例中Server类的事件定义部分稍作改动,将其改为下面的形式:

view plaincopy to clipboardprint?
  1. private readonly object syncRoot_Started = new object();   
  2. private readonly object syncRoot_Stopped = new object();   
  3.   
  4. private ServerEventHandler m_StartedEventHandler;   
  5. private ServerEventHandler m_StoppedEventHandler;   
  6.   
  7. /// <summary>   
  8. /// 定义一个事件,当服务器正常启动后,触发该事件   
  9. /// </summary>   
  10. public event ServerEventHandler Started   
  11. {   
  12.     add   
  13.     {   
  14.         lock (syncRoot_Started)   
  15.         {   
  16.             m_StartedEventHandler += value;   
  17.         }   
  18.     }   
  19.     remove   
  20.     {   
  21.         lock (syncRoot_Started)   
  22.         {   
  23.             m_StartedEventHandler -= value;   
  24.         }   
  25.     }   
  26. }   
  27.   
  28. /// <summary>   
  29. /// 定义一个事件,当服务器正常结束后,触发该事件   
  30. /// </summary>   
  31. public event ServerEventHandler Stopped   
  32. {   
  33.     add   
  34.     {   
  35.         lock (syncRoot_Stopped)   
  36.         {   
  37.             m_StoppedEventHandler += value;   
  38.         }   
  39.     }   
  40.     remove   
  41.     {   
  42.         lock (syncRoot_Stopped)   
  43.         {   
  44.             m_StoppedEventHandler -= value;   
  45.         }   
  46.     }   
  47. }   
  48.   
  49. protected virtual void DoStarted(object sender, ServerEventArgs e)   
  50. {   
  51.     if (m_StartedEventHandler != null)   
  52.         m_StartedEventHandler(sender, e);   
  53. }   
  54.   
  55. protected virtual void DoStopped(object sender, ServerEventArgs e)   
  56. {   
  57.     if (m_StoppedEventHandler != null)   
  58.         m_StoppedEventHandler(sender, e);   
  59. }   

现在,我们新加入了用于同步的对象syncRoot_Started和syncRoot_Stopped,它们被定义为Server的私有只读成员;在定义事件处理列表添加与移除的逻辑里,使用lock关键字实现线程同步,确保对于同一个事件的调用列表,在同一时刻只有一个线程对其进行操作。在前面的事件实现过程中,由于我们使用默认的add和remove方法,因此C#编译器会自动生成一个类似于上述代码中m_StartedEventHandler、m_StoppedEventHandler的私有成员,而在自定义的实现方式里,开发人员必须手工添加这样的私有成员。

C#中的属性可以是只包含get的只读属性,可以是只包含set的只写属性,还可以是既包含get又包含set的读写属性;而event的定义不同,add和remove必须成对出现。

还有一种情况下,会用add和remove来自定义事件的处理过程的添加与移除,就是当某个对象需要向外界公布多个事件时,此时,没有必要针对每个事件都定义一个私有成员,具体做法是,在类中定义一个集合(比如字典),在add中,向集合添加事件处理过程,而在remove中,将事件处理过程从集合中移除。我们再次改造上述实例,通过使用System.ComponentModel.EventHandlerList类来实现这样的效果:

view plaincopy to clipboardprint?
  1. private readonly object syncRoot_Started = new object();   
  2. private readonly object syncRoot_Stopped = new object();   
  3.   
  4. //private ServerEventHandler m_StartedEventHandler;   
  5. //private ServerEventHandler m_StoppedEventHandler;   
  6. private readonly object eventStarted = new object();   
  7. private readonly object eventStopped = new object();   
  8.   
  9. private EventHandlerList eventHandlerList = new EventHandlerList();   
  10.   
  11. /// <summary>   
  12. /// 定义一个事件,当服务器正常启动后,触发该事件   
  13. /// </summary>   
  14. public event ServerEventHandler Started   
  15. {   
  16.     add   
  17.     {   
  18.         lock (syncRoot_Started)   
  19.         {   
  20.             // m_StartedEventHandler += value;   
  21.             eventHandlerList.AddHandler(eventStarted, value);   
  22.         }   
  23.     }   
  24.     remove   
  25.     {   
  26.         lock (syncRoot_Started)   
  27.         {   
  28.             // m_StartedEventHandler -= value;   
  29.             eventHandlerList.RemoveHandler(eventStarted, value);   
  30.         }   
  31.     }   
  32. }   
  33.   
  34. /// <summary>   
  35. /// 定义一个事件,当服务器正常结束后,触发该事件   
  36. /// </summary>   
  37. public event ServerEventHandler Stopped   
  38. {   
  39.     add   
  40.     {   
  41.         lock (syncRoot_Stopped)   
  42.         {   
  43.             // m_StoppedEventHandler += value;   
  44.             eventHandlerList.AddHandler(eventStopped, value);   
  45.         }   
  46.     }   
  47.     remove   
  48.     {   
  49.         lock (syncRoot_Stopped)   
  50.         {   
  51.             // m_StoppedEventHandler -= value;   
  52.             eventHandlerList.RemoveHandler(eventStopped, value);   
  53.         }   
  54.     }   
  55. }   
  56.   
  57. protected virtual void DoStarted(object sender, ServerEventArgs e)   
  58. {   
  59.     ServerEventHandler startedHandler = (ServerEventHandler) eventHandlerList[eventStarted];   
  60.     if (startedHandler != null)   
  61.         startedHandler(sender, e);   
  62. }   
  63.   
  64. protected virtual void DoStopped(object sender, ServerEventArgs e)   
  65. {   
  66.     ServerEventHandler stoppedHandler = (ServerEventHandler) eventHandlerList[eventStopped];   
  67.     if (stoppedHandler != null)   
  68.         stoppedHandler(sender, e);   
  69. }   
  70.  

你可能感兴趣的:(C#)