可以认为委托是持有一个或多个方法的对象。当然,正常情况下你不想“执行”一个对象,但委托与典型对象不同。可以执行委托,这时委托会执行它所“持有”的方法。
我们从下面的示例代码开始。具体细节将在本章剩余内容介绍。
代码开始部分声明了一个委托类型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或PrintHigh)
如果你有C++背景,理解委托最快的方法是把它看成一个类型安全的、面向对象的C++函数指针
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; //声明委托变量 var rand=new Random(); var randomValue=rand.Next(99); del=randomValue<50 ?new MyDel(program.PrintLow) :new MyDel(program.PrintHigh); del(randomValue); //执行委托 } }
委托概述委托和类一样,是用户自定义类型。但类表示的是数据和方法的集合,而委托持有一个或多个方法,以及一系列预定义操作。
可以通过以下操作步骤来使用委托。
声明一个委托类型。委托声明看上去和方法声明相似,只是没有实现块
使用该委托类型声明一个委托变量
创建委托类型的对象,把它赋值给委托变量。新的委托对象包括指向某个方法的引用,这个方法和第一步定义的签名和返回类型一致
你可以选择为委托对象增加其他方法。这些方法必须与第一步中定义的委托类型有相同的签名和返回类型
在代码中你可以像调用方法一样调用委托。在调用委托时,其包含的每个方法都会被执行
你可以把delegate看做一个包含有序方法列表的对象,这些方法的签名和返回类型相同。
方法的列表称为调用列表
委托保存的方法可以来自任何类或结构,只要它们在下面两点匹配
委托的返回类型
委托的签名(包括ref和out修饰符)
调用列表中的方法可以是实例方法也可以是静态方法
在调用委托时,会执行其调用列表中的所有方法
声明委托类型与类一样,委托类型必须在被用来创建变量以及类型的对象前声明。声明格式如下。
关键字 委托类型名 ↓ ↓ delegate void MyDel(int x); ↑ ↑ 返回类型 签名
虽然委托类型声明看上去和方法声明一样,但它不需要在类内部声明,因为它是类型声明。
创建委托对象委托是引用类型,因此有引用和对象。委托类型声明后,我们可以声明变量并创建类型的对象。
有两种创建委托对象的方法,一种是使用带new运算符的对象创建表达式,如下面代码所示。
delVar=new MyDel(myInstObj.MyM1); dVar=new MyDel(SClass.OtherM2);
我们还可以使用快捷语法,它仅由方法说明符构成。这种快捷语法能够工作是因为在方法名称和其相应的委托类型间存在隐式转换。
delVar=myInstObj.MyM1; dVar=SClass.OtherM2;
创建委托对象会为委托分配内存,还会把第一个方法放入委托调用列表。 给委托赋值
由于委托是引用类型,我们可以通过给它赋值来改变包含在委托变量中的引用。旧的委托对象会被GC回收。
MyDel delvar; delVar=myInstObj.MyM1; ... delVar=SClass.OtherM2;
组合委托