四.封装与事件的引入
  下面我们要用面向对象的思想将上述代码进行封装,使其变清晰。

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Delegate
8 {
9     public delegate void math(int x);
10     public class Calcu
11     {
12         public math calcu;
13     }
14
15     class Program
16     {
17         static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); }
18         static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); }
19
20         static void Main(string[] args)
21         {
22             Calcu c = new Calcu();
23             c.calcu += square;
24             c.calcu += cube;
25             c.calcu(2);
26             Console.ReadKey();
27         }
28     }
29 }

  由于委托变量是public的,封装的程度很低,在外部可以任意修改。为了改进这个问题,C#引入了事件。
  所谓事件,实际上还是委托的实例化,只是其内部多了一些定义,多了一些限制。其一,事件实际上声明了一个private类型的委托变量,因此在类外无法直接调用。
  于是我们将上述代码的第12行改成这样:
  public event math calcu;
  运行之后25行报错了,因为calcu是private的,不能直接调用。但23,24行并没有报错。那么问题来了,为什么我们可以用+=来给calcu绑定方法呢?
  因为其二,事件还帮我们干了一件事情,是定义了绑定方法和取消绑定方法的函数,它们是public的,并且将运算符+=,-=重载,和这两个函数对应。
  好了,现在我们要写一个接口函数来完成计算:

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Delegate
8 {
9     public delegate void math(int x);
10     public class Calcu
11     {
12         public event math calcu;
13         public void calculate(int x)
14         {
15             calcu(x);
16         }
17     }
18
19     class Program
20     {
21         static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); }
22         static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); }
23
24         static void Main(string[] args)
25         {
26             Calcu c = new Calcu();
27             c.calcu += square;
28             c.calcu += cube;
29             c.calculate(2);
30             Console.ReadKey();
31         }
32     }
33 }

  至此,基本概念已经清晰。
  想来,使用事件会让人不得不将对象封装起来,这应该是面向对象思想的体现吧。