委托是一种定义方法的类,这样就可以使得方法A,可以像string类、int类一样当做方法B的参数进行传递。这种将方法动态地赋值给参数的做法,可以避免在代码中大量使用if-else(or switch)语句,同时使得程序具有更好的可扩展性。委托被大量使用在WPF中(至少我是这么认为的)。但是委托类不同于string类和int类的区别在于,可以将多个方法赋给同一个委托,或者说多个方法可以绑定到同一个委托类上,当调用该委托时,将依次调用其所绑定的方法,但是string类和int类,后面绑定的参数将会替换掉前一个参数。
事件用于封装委托类。当使用string类时,可以通过属性对字段进行封装,某个string类可以只读的,也可以是只写的。使用event关键字,声明一个事件也就是声明了一个进行了封装的委托类型变量,比如下面这条代码:
public event PropertyChangedEventHandler PropertyChanged;
其中,PropertyChangedEventHandler是一个委托类,event关键字定义了一个封装该委托的PropertyChanged事件。事件封装了委托,那么就可以将方法注册到事件中,当事件发生时,会依次调用注册了该事件的方法。比如在WPF中,给一个button控件添加Click方法,其实就是将Btn_Click方法注册到button控件的Click事件中,即button.Click += Btn_Click.
.NET Framework中对委托和事件编写的规范:
-
委托类型的名称都应该以EventHandler结尾;
-
委托的返回值是void(最好),并接受两个输入参数,一个是Object类,一个EventArgs类(或继承自EventArgs);
-
事件的命名为委托去掉EventHandler之后剩余的部分;
-
继承自EventArgs的类型应该以EventArgs结尾;
-
订阅事件的方法命名,通常为On+事件名。
Example:这个例子来源于张子阳博客中的例子,我最开始学习委托和事件也是看了这篇博客,所以我的这篇文章算是学习了委托和事件之后的一个整理,目的是加深自己的记忆。张子阳的博客地址如下:
http://www.tracefact.net/tech/009.html
http://www.tracefact.net/tech/029.html
例子是这样的,假设有一台热水器,当加热到指定温度时会提醒用户,则有一个加热方法,还有一个提醒方法。提醒方法要注册加热事件,当温度达到指定值时,调用提醒方法。
Heater类
public class Heater { private int temperature; // 定义一个名为BoiledEventHandler的委托类,两个参数,一个object类,一个是继承自EventArgs类的BoiledEventArgs类 public delegate void BoiledEventHandler(object sender, BoiledEventArgs e); // 定义一个封装BoiledEventHandler委托的事件 public event BoiledEventHandler Boiled; // 订阅Boiled事件的方法 protected virtual void OnBoiled(BoiledEventArgs e) { // 如果有方法注册了该事件,则调用所有注册了该事件的方法 if (Boiled != null) Boiled(this, e); } // Heater类中有一个加热的方法 public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; if (i % 10 == 0 && i <=95) Console.WriteLine("Temperature is {0}.", i); if(temperature > 95) { BoiledEventArgs e = new BoiledEventArgs(temperature); OnBoiled(e); } } } }
Alarm类
public class Alarm { public void MakeAlert(object sender, BoiledEventArgs e) { Heater heater = sender as Heater; Console.WriteLine("Alarm : Temperature is {0}.", e.temperature); } }
客户端程序
class Program { static void Main(string[] args) { Heater heater = new Heater(); Alarm alarm = new Alarm(); // 将Alarm中的MakeAlert方法注册到Heater的Boiled事件中 heater.Boiled += alarm.MakeAlert; heater.BoilWater(); Console.Read(); } }
源代码github地址: