.net委托与事件
很久没有写文章了,最近看了点书,有点小感悟,写出来,以纪念曾逝去的青春,纯属自娱,写的有不对的地方,望各位同仁批评
指正。
目录:
1.普通调用与回调
2.用委托实现回调
3.委托与事件
进入正题。
一,普通调用与回调
普通调用,也是我们最常用的调用,往往是高层代码(应用程序)调用低层的函数(如系统函数,库函数等) 。
回调(callback),指的是可以作为参数传给其他代码的一段可执行代码.回调时,则是在低层函数执行时调用高层的代码。
如果高层和低层分别是一个实体的话,那么普通调用实现的是上调用下,回调实现的是下调用上,这样就实现了高层与低层之间的
双向通信。
回调举例:
如果我们用js异步调用webservice的话,经常会传递两个函数,分别是执行成功和失败时执行的函数,实际上这两个函数
就是webservice的回调函数。当我们将函数传递过去后,webservice将调用的方法执行完后,报告我们的成功和失败函数.即
我们调用Webservice的方法,webservice触发间接调用我们的方法,实现双向调用。
二,用委托实现回调
历史上,Windows API经常使用C语言风格的函数指针来创建回调函数,使用回调,程序员可以使一个函数返回报告(即回调)
给程序中的另一个函数.不过,C语言风格回调函数的缺点在于,它们除了原始内存地址外无法表示其他信息,理想中的回调应该包
含更多类型安全信息,例如参数的数量与类型,所指向方法的返回值(有的话)。尽管如此,回调仍然很有用。
.net中的回调就是使用更为安全和面向对象的委托来完成的。本质上来讲,委托是一个类型安全的对象,它指向程序中另一个以
后会被调用的方法。
回调实例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
namespace DelegateTest { class Program { static void Main(string[] args) { Car car = new Car("跑车", 100, 40); car.RegisterCarEngine(OnCarEngineHandler); car.Accelerate(70); Console.Read(); } static void OnCarEngineHandler(int maxsd, int currsd) { if (currsd >= maxsd) { Console.WriteLine(String.Format("已经超速,当前速度为:{0}",currsd)); } else if (currsd > maxsd - 10) { Console.WriteLine(String.Format("离最大速度已经小于10,当前速度已经到:{0}",currsd)); } else { Console.WriteLine("哥们,没事,正常速度."); } } } class Car { public int CurrentSpeed { get; set; } public int MaxSpeed { get; set; } public string PetName { get; set; } public Car(string name,int maxSp,int currSp) { PetName = name; MaxSpeed = maxSp; CurrentSpeed = currSp; } public delegate void CarEngineHandler(int maxSpd,int currSpd); private CarEngineHandler carEngineHandler; public void RegisterCarEngine(CarEngineHandler carenginehandler) { carEngineHandler += carenginehandler; } public void Accelerate(int delta) { if (carEngineHandler != null) { carEngineHandler.Invoke(MaxSpeed, CurrentSpeed+delta); } } } }
三,委托与事件
本质上,事件只是委托的封装,就像一个语法糖一样
委托变量必须定为私有,否则为引发两个问题:
1.调用者可以把委托变量重新赋值,这样就删除了当前要调用的方法列表
2.调用者可以直接调用委托变量的方法列表
既然委托变量必须定位私有的,就要为委托变量创建自定义的注册和注销方法来保护封装等 而如果定义该委托的事件变量,就可
以省去这些代码量.定义事件变量之后,有相应缺点的两个好处:
1.事件的操作符只有两个+=和-=,这样就不会引发覆盖方法列表的情况
2.调用者不可直接调用事件的方法列表
事件实例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
namespace EventTest { class Program { static void Main(string[] args) { Car car = new Car("跑车", 100, 20); car.Exploded += OnAboutToBlowHandler; car.AboutToBlow += OnAboutToBlowHandler; car.Accelerate(100); Console.Read(); } static void OnExplodedHandler(Car car,CarEventArgs e) { if (car != null) { Console.WriteLine(String.Format("{0},要被罚款了啊,当前已超过最高速度:{1}公里",e.msg,car.CurrentSpeed-car.MaxSpeed)); } } static void OnAboutToBlowHandler(Car car, CarEventArgs e) { if (car != null) { Console.WriteLine(String.Format("{0},小心,当前速度,离最高速度还有:{1}公里", e.msg, car.MaxSpeed - car.CurrentSpeed)); } } } public class CarEventArgs : EventArgs { public readonly string msg; public CarEventArgs(string message) { msg = message; } } public class Car { public delegate void CarEngineHandle<T>(T eventSourceObject ,CarEventArgs args); public event CarEngineHandle<Car> Exploded; public event CarEngineHandle<Car> AboutToBlow; public int MaxSpeed { get; set; } public int CurrentSpeed { get; set; } public String PetName { get; set; } public Car(String name, int maxSd, int currSd) { PetName = name; MaxSpeed = maxSd; CurrentSpeed = currSd; } public void Accelerate(int delta) { if (CurrentSpeed + delta > MaxSpeed) { if (Exploded != null) { Exploded(this,new CarEventArgs("老兄,严重超速了啊")); } } else { CurrentSpeed += delta; if (CurrentSpeed + 10 > MaxSpeed) { if (AboutToBlow != null) { AboutToBlow(this,new CarEventArgs("老兄,快超速了啊")); } } else { Console.WriteLine("兄弟,没事,正常速度."); } } } } }