什么是委托
可以认为委托是持有一个或多个方法的对象。
下面我们讲提供创建和使用委托的语法和语义。在后面你将看到如何使用委托将可执行的代码从一个方法传递到另一个,以及为什么这样做是非常有用的。
我们将从下面的示例代码开始。如果此时你有些东西弄不明白,不必担心,我会在本章剩余内容中介绍委托的细节。
代码开始部分声明了一个委托类型MyDel
Program类声明了3个方法:PrintLow、PrintHigh和Main。接下来要创建的委托对象将持有PrintLow或PrintHigh方法,但到底使用哪个要到运行时才能确定。
Main声明了一个局部变量del,将持有一个MyDel类型的委托对象的引用。这并不会创建对象,只是创建持有委托对象引用的变量,在几行之后便会创建这个委托对象,并将其赋值给这个变量。
Main创建了一个Random类的对象,这是一个随机数生成器类。接着程序调用该对象的Next方法,将99作为方法的输入参数。这会返回介于0到99之间的随机整数,并将这个值保存在局部变量randomValue中。
下面一行检查这个返回并存储的随机值是否小于50(注意,我们使用三元条件运算符来返回两个委托之一。)
如果该值小于50,就创建一个MyDel委托对象并初始化,让它持有PrintLow方法的引用。
否则,就创建一个持有PrintHigh方法的引用的MyDel委托对象。
最后,Main执行委托对象del,这将执行它持有的方法(PrintLow或PrintHight)。
delegate void MyDel(int value); //声明委托类型
class Program{
void PrintLow( int value )
{
Console.WriteLine( "{0} - Low Value", value );
}
void PrintHigh( int value )
{
Console.WriteLine( "{0} - High Value", value );
}
static void Main( )
{
Program program = new Program();
MyDel del; //声明委托变量
//创建随机整数生成器对象,并得到0到99之间的一个随机数
Random rand = new Random();
int randomValue = rand.Next( 99 );
//创建一个包含PrintLow或PrintHigh的委托对象并将其赋值给del变量
del = randomValue < 50
? new MyDel( program.PrintLow )
: new MyDel( program.PrintHigh );
del( randomValue ); //执行委托
}}
由于我们使用了随机数生成器,程序在不同的运行过程中会产生不同的值。某次运行可能产生的结果如下:
38 - Low Value
委托概述
委托和类一样,是一种用户自定义的类型。但类表示的是数据和方法的集合,而委托则持有一个或多个方法,以及一些列预定义操作。可以通过以下操作步骤来使用委托,我们将在之后的内容中逐个解释每步操作。
(1) 声明一个委托类型。委托声明看上去和方法声明相似,只是没有实现。
(2) 使用该委托类型声明一个委托变量。
(3) 创建委托类型的对象,把它赋值给委托变量。新的委托对象包括指向某个方法的引用,这个方法和第一步定义的签名和返回类型一致。
(4) 你可以选择为委托对象增加其他方法。这些方法必须与第一步中定义的委托类型有相同的签名和返回类型。
(5) 在代码中你可以像调用方法一样调用委托。在调用委托的时候,其包含的每一个方法都会被执行。
委托的声明
正如我上节所述,委托是类型,就好像类是类型一样。与类一样,委托类型必须在被用来创建变量以及类型的对象之前声明。如下示例代码声明了委托类型。
delegate void MyDel( int x );
创建委托对象
委托是引用类型,因此有引用和对象。在委托类型声明之后,我们可以声明变量并创建类型的对象。如下代码演示了委托类型的变量声明:
MyDel delVar;//创建委托对象
delVar = new MyDel( myInstObj.MyM1 ); //方法一 用new进行初始化
delVar = myInstObj.MyM1; //方法二 直接赋值
组合委托
委托可以使用额外的运算符来“组合”。这个运算最终会创建一个新的委托,其调用列表连接了作为操作数的两个委托的调用列表副本。
例如,如下代码创建了3个委托。第3个委托由前两个委托组合而成。
MyDel delA = myInstObj.MyM1;MyDel delB = SClass.OtherM2;
MyDel delC = delA + delB; //组合调用列表
为委托添加方法
MyDel delVar = inst.MyM1; //创建并初始化
delVar += SCl.m3; //增加方法
delVar += X.Act; //增加方法
从委托移除方法
delVar -= SCl.m3; //从委托移除方法
委托的示例
如下代码定义并使用了没有参数和返回值的委托。有关代码的注意事项如下。
//定义一个没有返回值和参数的委托类型delegate void PrintFunction();
class Test{
public void Print1()
{ Console.WriteLine("Print1 -- instance"); }
public static void Print2()
{ Console.WriteLine("Print2 -- static"); }}
class Program{
static void Main()
{
Test t = new Test(); //创建一个测试类实例
PrintFunction pf; //创建一个空委托
pf = t.Print1; //实例化并初始化该委托
//给委托增加3个另外的方法
pf += Test.Print2;
pf += t.Print1;
pf += Test.Print2;
//现在,委托含有4个方法
if( null != pf ) //确认委托有方法
pf(); //调用委托
else
Console.WriteLine("Delegate is empty");
}}
输出:
Print1 -- instance
Print2 -- staticPrint1 -- instance
Print2 – static
调用带返回值的委托
delegate int MyDel( ); //声明有返回值的方法class MyClass {
int IntValue = 5;
public int Add2() { IntValue += 2; return IntValue;}
public int Add3() { IntValue += 3; return IntValue;}}
class Program {
static void Main( ) {
MyClass mc = new MyClass();
MyDel mDel = mc.Add2; //创建并初始化委托
mDel += mc.Add3; //增加方法
mDel += mc.Add2; //增加方法
Console.WriteLine("Value: {0}", mDel() );
}
}
输出:
Value: 12
调用带引用参数的委托
delegate void MyDel( ref int X );
class MyClass{
public void Add2(ref int x) { x += 2; }
public void Add3(ref int x) { x += 3; }
static void Main()
{
MyClass mc = new MyClass();
MyDel mDel = mc.Add2;
mDel += mc.Add3;
mDel += mc.Add2;
int x = 5;
mDel(ref x);
Console.WriteLine("Value: {0}", x);
}}
输出:
Value: 12
匿名方法
委托类型的返回类型
delegate int OtherDel(int InParam);
static void Main(){
//匿名函数
OtherDel del = delegate(int x)
{
return x + 20 ; //返回一个整型值
};
}