C#学习之事件
.NET的事件模型是建立在委托的机制上,事件机制可以做到,原生的委托也都可以做到;可以说,事件只是对委托的封装,使得用起来更安全。
在具体的代码里,定义一个委托和定义一个事件的差别仅仅是:定义事件时要前面加一个 event 关键字!
正因为这个关键字,编译器就会为这个被封装了的委托暗地里做很多事情,如原生委托可以直接用new来初始化,可以在委托链绑定了很多方法的时候直接用一个 = 操作符来把那些方法清空,等等,而对于事件,编译器把这些都封装了,不能乱来,编译器只是提供了两个方法:add_myEvent、remove_myEvent 让事件客户端仅能通过 += 、 -= 来添加、移除事件的订阅者,如果没有订阅者(也就是委托链为空)时触发事件,那什么也不会发生,等等
一切尽在代码,不废话了
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 using System.Threading; 7 8 9 namespace test 10 { 11 12 //定义消息类 13 class CalculateEventAgrs:EventArgs 14 { 15 public readonly int x, y; 16 public CalculateEventAgrs(int x, int y) 17 { 18 this.x = x; 19 this.y = y; 20 } 21 } 22 23 24 //定义事件发布类 25 class Calculator 26 { 27 //定义一个代理类,声明事件委托 28 public delegate void CalculateEventHandler(object sender, CalculateEventAgrs e); 29 30 //定义事件成员,代理类类型,提供外部绑定 31 public event CalculateEventHandler MyCalculate; 32 33 //提供受保护的虚方法,可以由子类覆写来拒绝监视 34 protected virtual void OnCalculate(CalculateEventAgrs e) 35 { 36 //如果没有订阅者,什么都不做 37 if (MyCalculate != null) 38 { 39 //触发事件 40 MyCalculate(this, e); 41 } 42 } 43 44 45 //触发事件方法,也就是事件发生,可以理解为点击一下鼠标等事件 46 public void Calculate(int x, int y) 47 { 48 //生成事件发生时的消息 49 CalculateEventAgrs e = new CalculateEventAgrs(x,y); 50 51 //通知所有的 事件的注册者 52 OnCalculate( e); 53 } 54 55 } 56 57 58 //定义事件接收类/事件订阅者/ 59 class CalculatorManager 60 { 61 //事件处理函数,可以更改所在类(也就是事件订阅者)的一些属性等 62 public void Add(object sender, CalculateEventAgrs e) 63 { 64 Console.WriteLine(e.x + e.y); 65 } 66 67 //事件处理函数 68 public void Subtract(object sender, CalculateEventAgrs e) 69 { 70 Console.WriteLine(e.x - e.y); 71 } 72 } 73 74 75 class Program 76 { 77 static void Main(string[] args) 78 { 79 Calculator calculate = new Calculator();//事件发布者 80 81 CalculatorManager cm = new CalculatorManager();//事件订阅者/接收者 82 83 // calculate.MyCalculate = new Calculator.CalculateEventHandler(); 84 85 86 calculate.MyCalculate += cm.Add;//订阅事件:cm 这个对象主动去订阅 calculate对象里的MyCalculate事件 87 88 calculate.MyCalculate -= cm.Subtract;//取消订阅:如果委托链里没有这个事件,也不会抛出异常,什么也不做 89 90 calculate.Calculate(100,200);//事件发生 91 92 Console.ReadKey(); 93 } 94 95 } 96 }
在83行那里,如果去掉注释再编译的话,会提示错误如下:
如果用到:calculate.MyCalculate = cm.Add; 这句代码的话也会提示一样的错误。