委托是一种新的面向对象语言特性,在历史比较长的面向对象语言比如 C++中并未出现
过。微软公司在设计运行于 .NET Framework 平台之上的面向对象语言(如 C#和 Visual
Basic.NET)时引入了这一新特性。
7.1理解委托的概念
我们都很熟悉常用的数据类型(如 int)的使用方法:先定义一个变量,然后再给其赋
值,如下所示:
int i; //定义变量
i=100; //给变量赋值
委托(delegate)也可以看成是一种数据类型,可以用于定义变量。但它是一种特殊的
数据类型,它所定义的变量能接收的数值只能是一个函数,更确切地说,委托类型的变量可
以接收一个函数的地址,很类似于 C++语言的函数指针。
简单地说:
委托变量可看成是一种类型安全的函数指针,它只能接收符合其要求的函数地址。
来看一个例子(示例项目 FirstDelegateExample),这是一个控制台项目。
示例项目中定义了一个类 MathOpt,其中有一个方法 Add:
public class MathOpt
{
public int Add(int argument1, int argument2)
{
return argument1 + argument2;
}
}
示例项目接着定义了一个委托数据类型 MathOptDelegate,注意加粗的“delegate”关键
字:
public delegate int MathOptDelegate(int value1,int value2);
示例项目中上述定义语句放在两个类(MathOpt和 Program)之外。
定义好了委托数据类型,在 Main()方法中即可定义一个此委托类型的变量:
MathOptDelegate oppDel;
接着可以给此变量赋值:
MathOpt obj = new MathOpt();
oppDel = obj.Add;
您注意到了吗?委托变量接收一个对象的方法引用。
赋值之后的委托变量可以当成普通函数一样使用:
Console.WriteLine(oppDel(1, 2)); //输出 3
上述语句实际上相当于以下语句:
Console.WriteLine(obj.Add(1, 2)); //输出 3
示例项目 FirstDelegateExample的完整代码如下所示:
public class MathOpt
{
public int Add(int argument1, int argument2)
{
return argument1 + argument2;
}
}
public delegate int MathOptDelegate(int value1, int value2);
class Program
{
static void Main(string[] args)
{
MathOptDelegate oppDel;
MathOpt obj = new MathOpt();
oppDel = obj.Add;
Console.WriteLine(oppDel(1, 2)); //输出 3
}
}
从这个示例项目中可以得到这样一个直观的印象:委托可以看成是一个函数的“容器”,
将某一具体的函数“装入”后,就可以把它当成函数一样使用。
其实,委托并不是函数的“容器”,它是一个派生自 Delegate的类,但从使用角度出发,
将其理解为函数“容器”也是可以的。
那么,是不是所有的函数都可以赋值给委托类型 MathOptDelegate的变量 oppDel呢?
请注意 MathOptDelegate的定义语句,它规定了委托类型 MathOptDelegate的变量只能
接收这样的函数:
拥有两个 int 类型的参数,并且返回值类型也是 int。
只要是满足上述要求的函数,不管其名字如何,也不管它是静态的还是实例的,都可以
传给委托类型 MathOptDelegate的变量 oppDel,并通过 oppDel来“间接地”调用它们。
定义委托类型时对函数的要求被称为函数的“签名(signature)”。
函数的签名规定了函数的参数数目和类型,以及函数的返回值,体现了函数的本质特征。
每一个委托都确定了一个函数的签名。拥有不同签名的函数不能赋值给同一类型的委托
变量。
因此,一个委托类型的变量,可以引用任何一个满足其要求的函数。