为了账号安全,请及时绑定邮箱和手机立即绑定

C#基础教程:事件

标签:
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.  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消