首页 > 代码库 > C#——委托(1)

C#——委托(1)

什么是委托?
还记得C/C++语言里的函数指针吗?委托就是他的”升级版“。
先看一个简单的小程序:

 1 # include<stdio.h>
 2 
 3 typedef int(*Calc)(int a, int b);//使用typedef把他定义成一种数据类型
 4 
 5 int Add(int a,int b)
 6 {
 7     int result = a + b;
 8     return result;
 9 }
10 
11 int main(void)
12 {
13     int x = 100;
14     int y = 200;
15     int z = 0;
16 
17     z = Add(x,y);//直接调用
18     printf("%d+%d=%d\n",x,y,z);
19 
20     Calc cFun = &Add;//间接调用
21     z = cFun(x, y);
22     printf("%d+%d=%d\n", x, y, z);
23 
24     return 0;
25 }

 

技术分享

直接调用和间接调用他们的运行结果是一样的
变量和函数到底是啥?
变量(代表数据)是以变量名对应的内存地址为起点的一段内存中所存储的值
函数(代表算法)是以函数名对应的内存地址为起点的一段内存中所存储的一组机器语言指令
知道了啥是变量和函数,那就来看看啥是 直接调用和间接调用
直接调用:通过函数名来调用函数,CPU通过函数名直接获得函数所在地址并开始执行,执行完函数后CPU返回调用者那里继续往下执行
间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值(函数名所对应的地址)获得函数所在地址并开始执行,最终返回调用者那里继续往下执行
下面我们就看看委托是个什么东西

 1 namespace DelegateExample_Action_
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Calculator calculator = new Calculator();
 8             Action action = new Action(calculator.Report);
 9             action.Invoke();//间接引用
10             /*
11             还可以这么写
12             action();
13             */
14             calculator.Report();//直接引用
15             //运行结果完全一样
16         }
17     }
18 
19     class Calculator
20     {
21         public  void Report()
22         {
23             Console.WriteLine("I have three methods.");
24         }
25         public  int Add(int a, int b)
26         {
27             int result = a + b;
28             return result;
29         }
30         public int Sub(int a, int b)
31         {
32             int result = a - b;
33             return result;
34         }
35     }
36 }

 

IDE提示到,你要往里面放一个返回值为void类型,参数列表为空的一个方法,那么在Calculator类里符合的就是Report方法,所以我们就把Report方法放了进去

技术分享

运行结果:

技术分享

第一行是我们直接调用时打印出来的语句,第二行是我们用Action委托打印出来的语句
如果要调用Add或者Sub方法,我们选择使用Func委托:

 1 namespace DelegateExample_Func_
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Calculator calculator = new Calculator();
 8 
 9             Func<int, int, int> Func1 = new Func<int, int, int>(calculator.Add);
10             Func<int, int, int> Func2 = new Func<int, int, int>(calculator.Sub);
11             int x = 100;
12             int y = 30;
13             int z = 0;
14             z = Func1.Invoke(x, y);
15             Console.WriteLine(z);
16             z = Func2.Invoke(x, y);
17             Console.WriteLine(z);
18         }
19     }
20 
21     class Calculator
22     {
23         public int Add(int a, int b)
24         {
25             int result = a + b;
26             return result;
27         }
28         public int Sub(int a, int b)
29         {
30             int result = a - b;
31             return result;
32         }
33     }
34 }

 

在打尖括号时,IDE提示我们他有17个重载,通过下翻会发现,它会增加参数的个数(最后的那个是返回值类型),我们要用他来引用Add和Sub方法,而这两个方法有两个参数,所以我们就选了图片里的那种情况,因为两个参数是int类型,所以返回的结果也一定是int类型 所以就用 Func<int,int,int>(Calculator.Add); (尖括号里前两个是参数类型,最后一个是返回值类型)

运行结果:

技术分享
自定义委托
以上的Action委托和Function委托,是微软已经为我们准备好的,那我们自己怎么声明呢,这就是接下来的自定义委托
先说明,委托是一种类(class),所以委托声明在名称空间内,和program类是平级的。如何查看委托是不是类呢,很简单的一个小程序:

 1 namespace DelegateExample_IsClass_
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Type t = typeof(Action);
 8             Console.WriteLine(t.IsClass);
 9         }
10     }
11 }

 

结果运行后打印出来的是 True ,这说明委托确实是个类
然后我们就自己声明一个委托,委托的声明格式是这样的:
可访问性 delegate关键字 目标方法返回值类型 委托名字(目标方法的参数列表);
下面看一个小程序:

 1 namespace DelegateExample_custom_delegate_
 2 {
 3     public delegate double Calc(double x,double y);
 4 
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Calculator calculator = new Calculator();
10             Calc calc = new Calc(calculator.Add);
11             Calc calc2 = new Calc(calculator.Sub);
12             Calc calc3 = new Calc(calculator.Mul);
13             Calc calc4 = new Calc(calculator.Div);
14 
15             double a = 100;
16             double b = 200;
17             double c = 0;
18 
19             c = calc.Invoke(a, b);
20             Console.WriteLine(c);
21             c = calc2.Invoke(a, b);
22             Console.WriteLine(c);
23             c = calc3.Invoke(a, b);
24             Console.WriteLine(c);
25             c = calc4.Invoke(a, b);
26             Console.WriteLine(c);
27 
28         }
29     }
30     class Calculator
31     {
32         public double Add(double x, double y)
33         {
34             return x + y;
35         }
36         public double Sub(double x, double y)
37         {
38             return x - y;
39         }
40         public double Mul(double x, double y)
41         {
42             return x * y;
43         }
44         public double Div(double x, double y)
45         {
46             return x / y;
47         }
48     }
49 }

 

这个程序中,我们自己声明了一个叫Calc的委托,因为我们的方法都是double的参数,double的返回值,所以是 "double Calc" 。剩下的就没什么大问题了。
自定义委托时有几点需要注意:
委托与所封装的方法必须“类型兼容”,也就是说
返回值的数据类型要一致
参数列表在个数和数据类型上一致(参数名不需要一样)
再就是声明的时候要声明在正确的位置处,要声明在名称空间中(与program平级)但是C#又允许嵌套类型存在,声明在Program类里又编译的过去,但不要这么干,该放哪就放哪(要放在名称空间里与其他类平级)

----------------------------------------------------------------------------------------------

迫于时间缘故,这篇博客就先写这么多,放假后会写完后面的

希望博友们指出我的问题所在,指出我哪里理解错了,共同交流,共同进步!

 To be continued!

C#——委托(1)