深入解析事件
1 事件的由来
在介绍事件之前大家可以先看看下面的例子, PriceManager 负责对商品价格进行处理,当委托对象 GetPriceHandler 的返回值大于100元,按8.8折计算,低于100元按原价计算。
1 public delegate double PriceHandler();
2
3 public class PriceManager
4 {
5 public PriceHandler GetPriceHandler;
6
7 //委托处理,当价格高于100元按8.8折计算,其他按原价计算
8 public double GetPrice()
9 {
10 if (GetPriceHandler.GetInvocationList().Count() > 0)
11 {
12 if (GetPriceHandler() > 100)
13 return GetPriceHandler()*0.88;
14 else
15 return GetPriceHandler();
16 }
17 return -1;
18 }
19 }
20
21 class Program
22 {
23 static void Main(string[] args)
24 {
25 PriceManager priceManager = new PriceManager();
26
27 //调用priceManager的GetPrice方法获取价格
28 //直接调用委托的Invoke获取价格,两者进行比较
29 priceManager.GetPriceHandler = new PriceHandler(ComputerPrice);
30 Console.WriteLine(string.Format("GetPrice\n Computer's price is {0}!",
31 priceManager.GetPrice()));
32 Console.WriteLine(string.Format("Invoke\n Computer's price is {0}!",
33 priceManager.GetPriceHandler.Invoke()));
34
35 Console.WriteLine();
36
37 priceManager.GetPriceHandler = new PriceHandler(BookPrice);
38 Console.WriteLine(string.Format("GetPrice\n Book's price is {0}!",
39 priceManager.GetPrice()));
40 Console.WriteLine(string.Format("Invoke\n Book's price is {0}!" ,
41 priceManager.GetPriceHandler.Invoke()));
42
43 Console.ReadKey();
44 }
45 //书本价格为98元
46 public static double BookPrice()
47 {
48 return 98.0;
49 }
50 //计算机价格为8800元
51 public static double ComputerPrice()
52 {
53 return 8800.0;
54 }
55 }
运行结果
观察运行的结果,如果把委托对象 GetPriceHandler 设置为 public ,外界可以直接调用 GetPriceHandler.Invoke 获取运行结果而移除了 GetPrice 方法的处理,这正是开发人员最不想看到的。
为了保证系统的封装性,开发往往需要把委托对象 GetPriceHandler 设置为 private, 再分别加入
AddHandler,RemoveHandler 方法对 GetPriceHandler 委托对象进行封装。
1 public delegate double PriceHandler();
2
3 public class PriceManager
4 {
5 private PriceHandler GetPriceHandler;
6
7 //委托处理,当价格高于100元按8.8折计算,其他按原价计算
8 public double GetPrice()
9 {
10 if (GetPriceHandler!=null)
11 {
12 if (GetPriceHandler() > 100)
13 return GetPriceHandler()*0.88;
14 else
15 return GetPriceHandler();
16 }
17 return -1;
18 }
19
20 public void AddHandler(PriceHandler handler)
21 {
22 GetPriceHandler += handler;
23 }
24
25 public void RemoveHandler(PriceHandler handler)
26 {
27 GetPriceHandler -= handler;
28 }
29 }
30 ................
31 ................
为了保存封装性,很多操作都需要加入AddHandler、RemoveHandler 这些相似的方法代码,这未免令人感到厌烦。
为了进一步简化操作,事件这个概念应运而生。
2 事件的定义
事件(event)可被视作为一种特别的委托,它为委托对象隐式地建立起add_XXX、remove_XXX 两个方法,用作注册与注销事件的处理方法。而且事件对应的变量成员将会被视为 private 变量,外界无法超越事件所在对象直接访问它们,这使事件具备良好的封装性,而且免除了add_XXX、remove_XXX等繁琐的代码。
1 public class EventTest
2 {
3 public delegate void MyDelegate();
4 public event MyDelegate MyEvent;
5 }
观察事件的编译过程可知,在编译的时候,系统为 MyEvent 事件自动建立add_MyEvent、remove_MyEvent 方法。
3 事件的使用方式
事件能通过+=和-=两个方式注册或者注销对其处理的方法,使用+=与-=操作符的时候,系统会自动调用对应的 add_XXX、remove_XXX 进行处理。
值得留意,在PersonManager类的Execute方法中,如果 MyEvent
绑定的处理方法不为空,即可使用MyEvent(string)引发事件。但如果在外界的 main 方法中直接使用 personManager.MyEvent
(string) 来引发事件,系统将引发错误报告。这正是因为事件具备了良好的封装性,使外界不能超越事件所在的对象访问其变量成员。
注意:在事件所处的对象之外,事件只能出现在+=,-=的左方。
此时,开发人员无须手动添加 add_XXX、remove_XXX 的方法,就可实现与4.1例子中的相同功能,实现了良好的封装。
1 public delegate void MyDelegate(string name);
2
3 public class PersonManager
4 {
5 public event MyDelegate MyEvent;
6
7 //执行事件
8 public void Execute(string name)
9 {
10 if (MyEvent != null)
11 MyEvent(name);
12 }
13 }
14
15 class Program
16 {
17 static void Main(string[] args)
18 {
19 PersonManager personManager = new PersonManager();
20 //绑定事件处理方法
21 personManager.MyEvent += new MyDelegate(GetName);
22 personManager.Execute("Leslie");
23 Console.ReadKey();
24 }
25
26 public static void GetName(string name)
27 {
28 Console.WriteLine("My name is " + name);
29 }
30 }
4 事件处理方法的绑定
在绑定事件处理方法的时候,事件出现在+=、-= 操作符的左边,对应的委托对象出现在+=、-= 操作符的右边。对应以上例子,事件提供了更简单的绑定方式,只需要在+=、-= 操作符的右方写上方法名称,系统就能自动辩认。
1 public delegate void MyDelegate(string name);
2
3 public class PersonManager
4 {
5 public event MyDelegate MyEvent;
6 .........
7 }
8
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 PersonManager personManager = new PersonManager();
14 //绑定事件处理方法
15 personManager.MyEvent += GetName;
16 .............
17 }
18
19 public static void GetName(string name)
20 {.........}
21 }
如果觉得编写 GetName 方法过于麻烦,你还可以使用匿名方法绑定事件的处理。
1 public delegate void MyDelegate(string name);
2
3 public class PersonManager
4 {
5 public event MyDelegate MyEvent;
6
7 //执行事件
8 public void Execute(string name)
9 {
10 if (MyEvent != null)
11 MyEvent(name);
12 }
13
14 static void Main(string[] args)
15 {
16 PersonManager personManager = new PersonManager();
17 //使用匿名方法绑定事件的处理
18 personManager.MyEvent += delegate(string name){
19 Console.WriteLine("My name is "+name);
20 };
21 personManager.Execute("Leslie");
22 Console.ReadKey();
23 }
24 }
来源:http://www.cnblogs.com/zhangyanhai/archive/2013/10/09/3359240.html