C# 事件

C# 和 .NET 是支持事件驱动编程的,但它的处理需要委托实现来调度事件,所以事件和委托是紧密关联(耦合性高)。

事件是允许类或对象的某些状态发生改变时通知其它类或对象。

.NET 中的事件遵循观察者设计模式,常用的设计模式不熟悉的可以网上查查。

发送或引发事件的类称为发布者,接收或处理事件的类称为订阅者。

声明事件步骤

要在类中声明事件,首先必须声明事件的委托类型,如下:

public delegate void Notify();
   
   

其次,声明事件,如下:

public event Notify ProcessCompleted;
   
   

第三,调用事件,如下:


   
   
  1. if(ProcessCompleted != null)
  2. ProcessCompleted();
  3. //或者
  4. //ProcessCompeleted?.Invoke();

只能在声明事件的类中调用事件。

第四,注册事件,如下:

sample.ProcessCompleted += Sample_ProcessCompeleted;
   
   

如果是要取消事件,如下:

sample.ProcessCompleted -= Sample_ProcessCompeleted;
   
   

完整代码:  


   
   
  1. public class EventSample
  2. {
  3. public delegate void Notify();
  4. public event Notify ProcessCompeleted;
  5. public void Start()
  6. {
  7. Console.WriteLine( "开始作业");
  8. //业务逻辑
  9. //处理完毕后触发事件
  10. OnProcessCompeleted();
  11. }
  12. protected virtual void OnProcessCompeleted()
  13. {
  14. ProcessCompeleted?.Invoke();
  15. //判断是否订阅了
  16. //if (ProcessCompeleted != null)
  17. // ProcessCompeleted();
  18. }
  19. }
  20. class Program
  21. {
  22. static void Main(string[] args)
  23. {
  24. EventSample sample = new EventSample();
  25. sample.ProcessCompeleted += Sample_ProcessCompeleted;
  26. sample.Start();
  27. Console.ReadLine();
  28. }
  29. private static void Sample_ProcessCompeleted()
  30. {
  31. Console.WriteLine( "处理完成");
  32. }
  33. }

上面,Start() 方法最后一行调用了 OnProcessCompeleted() ,这引发了一个事件,通常,要引发事件,应使用名称定义受保护的虚拟方法 On<EventName> 。protected 和 virtual 使派生类能够覆盖引发事件的逻辑。但是,派生类应始终调用 On<EventName> 基类方法,以确保注册的委托接收事件。

OnProcessCompleted()方法调用委托 ProcessCompleted?.Invoke();。这会调用事件中注册的所有事件处理程序方法。

Program 类是 ProcessCompeleted 事件的订阅者。它使用 += 运算符向事件注册。Sample_ProcessCompeleted() 是处理事件方法且与 Notify 委托声明的一致。

内置 EventHandler 委托

.NET 还内置了两个常用的委托类型 EventHandler 和 EventHandler<TEventArgs> 。通常,任何事件都应包括两个参数:事件源和事件数据。EventHandler 主要用于不包含事件数据;对包含事件数据的使用 EventHandler<TEventArgs> 。

先看 EventHandler 的使用。


   
   
  1. public class EventSample
  2. {
  3. //public delegate void Notify();
  4. public event EventHandler ProcessCompeleted;
  5. public void Start()
  6. {
  7. Console.WriteLine( "开始作业");
  8. //业务逻辑
  9. //处理完毕后触发事件
  10. OnProcessCompeleted(EventArgs.Empty);
  11. }
  12. protected virtual void OnProcessCompeleted(EventArgs e)
  13. {
  14. ProcessCompeleted?.Invoke( this, e);
  15. }
  16. }
  17. class Program
  18. {
  19. static void Main(string[] args)
  20. {
  21. EventSample sample = new EventSample();
  22. sample.ProcessCompeleted += Sample_ProcessCompeleted;
  23. sample.Start();
  24. Console.ReadLine();
  25. }
  26. private static void Sample_ProcessCompeleted(object sender,EventArgs e)
  27. {
  28. Console.WriteLine( "处理完成");
  29. }
  30. }

上面代码中,Sample_ProcessCompeleted() 方法多了两个与 EventHandler 匹配的参数。此外,当我们在方法中使用引发事件时,this 作为发送者传递。另外,我们的事件不需要数据,所以使用 EventArgs.Empty 。

传递事件数据

大多数事件都会向订阅者发送一些数据。EventArgs 类是所有事件数据的基类。.NET 还包含了其它的内置事件数据类,如:SerialDataReceivedEventArgs 。它遵循以 EventArgs 结尾的命名方式。我们可以通过继承 EventArgs 来自定义事件数据。


   
   
  1. public class ProcessCompeletedEventArgs : EventArgs
  2. {
  3. public bool IsCompeleted { get; set; }
  4. /// <summary>
  5. /// 完成时间
  6. /// </summary>
  7. public DateTime CompeletedAt { get; set; }
  8. }
  9. public class EventSample
  10. {
  11. //public delegate void Notify();
  12. public event EventHandler<ProcessCompeletedEventArgs> ProcessCompeleted;
  13. public void Start()
  14. {
  15. Console.WriteLine( "开始作业");
  16. //业务逻辑
  17. ProcessCompeletedEventArgs e = new ProcessCompeletedEventArgs
  18. {
  19. IsCompeleted = true,
  20. CompeletedAt =DateTime.Now
  21. };
  22. //处理完毕后触发事件
  23. OnProcessCompeleted(e);
  24. }
  25. protected virtual void OnProcessCompeleted(ProcessCompeletedEventArgs e)
  26. {
  27. ProcessCompeleted?.Invoke( this, e);
  28. }
  29. }
  30. class Program
  31. {
  32. static void Main(string[] args)
  33. {
  34. EventSample sample = new EventSample();
  35. sample.ProcessCompeleted += Sample_ProcessCompeleted;
  36. sample.Start();
  37. Console.ReadKey();
  38. }
  39. private static void Sample_ProcessCompeleted(object sender, ProcessCompeletedEventArgs e)
  40. {
  41. Console.WriteLine( "IsCompeleted:{0},CompletedAt:{1}", e.IsCompeleted, e.CompeletedAt);
  42. Console.WriteLine( "处理完成");
  43. }
  44. }

 总结

我们总结下事件的一些要点:

  1. 事件是委托的封装,以防止委托的用户重置委托及其调用列表,并且只允许在调用列表中添加或删除目标

  2. 一些常用的事件尽量使用内置 EventHandler 或 EventHandler<TEventArgs>

  3. 发布者类引发一个事件(发布者确定何时引发事件),订阅者类注册一个事件并提供事件的处理方法(订阅者确定采取什么动作来响应)

  4. 处理事件的方法必须与委托声明的保持一致

  5. 使用 += 运算符注册事件;使用 -= 运算符取消订阅

  6. 尽量使用 EventHandler<TEventArgs> 来传递事件数据,TEventArgs 是泛型保证类型安全

  7. 可以继承 EventArgs 来自定义事件数据

  8. 事件可以声明为静态、虚拟、密封和抽象

  9. 接口可以包含事件

  10. 一个事件可以有多个订阅者

  11. 如果有多个订阅者,则同步调用事件处理程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值