前言
.net平台的开发人员肯定都知道委托,但是对于菜鸟级成员来说,对委托的深入了解却不是一件很容易的事情。
比如我就长期处于迷惑的状态。后来逐渐看一些书及文章,才渐渐清晰一些了。
发现其实委托也不是多高深的东西,前面的困惑应该是学习方法不当导致的结果(部分培训机构及劣质书籍)。
下面是个人目前对委托的了解,不一定准确完善,只期抛砖引玉。
相关概念
*函数指针:保存 函数首地址的 变量。
函数指针是一个变量,只不过其中保存的不是数据,而是一个地址值,是某一个函数的地址值。
*委托
.net平台的委托是一种特殊的函数指针,他使用对象(代替了变量)来保存函数地址,其中加入了函数签名机制,从而保证了类型的安全。
缘起
什么情况下会用到委托(函数指针)呢?下面是《c#本质论》一书中列举的几个场景:
● 启动线程—— 在 C#中,可以告诉计算机并行运行某些新的执行序列。这种序列就称为线程,
在基类 System.Threading.Thread 的一个实例上使用方法 Start(),就可以开始执行一个线程。
如果要告诉计算机开始一个新的执行序列,就必须说明要在哪里执行该序列。
必须为计算机提供开始执行的方法的细节,即 Thread.Start()方法必须带有一个参数,该参数定义了要由线程调用的方法。
● 通用库类—— 有许多库包含执行各种标准任务的代码。这些库通常可以自我包含。
这样在编写库时,就会知道任务该如何执行。但是有时在任务中还包含子任务,只有使用该库的客户机代码才知道如何执行这些子任务。
例如编写一个类,它带有一个对象数组,并把它们按升序排列。
但是,排序的部分过程会涉及到重复使用数组中的两个对象,比较它们,看看哪一个应放在前面。
如果要编写的类必须能给任何对象数组排序,就无法提前告诉计算机应如何比较对象。
处理类中对象数组的客户机代码也必须告诉类如何比较要排序的对象。换言之,客户机代码必
须给类传递某个可以进行这种比较的合适方法的细节。
● 事件—— 一般是通知代码发生了什么事件。GUI 编程主要是处理事件。
在发生事件时,运行库需要知道应执行哪个方法。这就需要把处理事件的方法传送为委托的一个参数。
一、 声明委托
① delegate string GetAString(); --无参,返回string类型。
② delegate void IntMethodInvoker(int x); --一个int类型参数,无返回值。
③ delegate double TwoLongsOp(long first, long second); --两个long类型参数,返回double类型。
声明委托的语法类似于方法的定义,但没有方法体,定义的前面要加上关键字 delegate。
因为定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,
既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。
根据定义的可见性,可以在委托定义上添加一般的访问修饰符:public、 private 和 protected 等。
二、 使用委托
private delegate string GetAString();
static void Main
{
int x = 40;
GetAString firstStringMethod = new GetAString(x.ToString);
Console.WriteLine("String is" + firstStringMethod());
// With firstStringMethod initialized to x.ToString(),
// the above statement is equivalent to saying
// Console.WriteLine("String is" + x.ToString());
}
在这段代码中,实例化了类型为 GetAString 的一个委托,并对它进行初始化,使它引
用整型变量 x 的 ToString()方法。
*firstStringMethod()等价于firstStringMethod. Invoke();
其他
委托的一个特征是它们的类型是安全的,可以确保被调用的方法签名是正确的。但有
趣的是,它们不关心在什么类型的对象上调用该方法,甚至不考虑该方法是静态方法,
还是实例方法。
最后
基本篇就到这里。
.net平台对于委托还有一些扩展,在下一篇博客讨论。
ps:基本上算是第一次写技术博客,再加上水平及其有限,肯定有很多不足,还望大家指正。