标签:
1. 委托概述
这是一个新的概念,但是其本质并不是什么新鲜的事物,委托本质上就是一个类。只不过一般的类是数据的集合,委托保存的是一个或者多个方法。委托是引用类型,因此委托有引用和对象,同时委托对象中包含指向方法的引用,也就是C++中的函数指针的概念。也就是说委托中的数据成员都是一些函数指针,这些函数指针指向的方法和委托类型有相同的函数签名。
从上图中可以看出,委托和类基本上就是一个东西,过程都是一样的:
声明一个类型->声明该类型的引用变量(在栈中)->利用new在堆中创建实例对象,同时利用构造函数传参数,只不过委托实例利用默认的构造函数初始化调用列表->使用变量,通过引用变量,使用该类型的对象。
类对象的数据部分保存的是一般的数据类型 ,委托对象的数据部分保存的是函数指针,这些函数指针挨着盘的存放,构成了调用列表。
2. 声明委托类型
委托是类型,就好像类是类型一样,所以委托类型必须在被用来创建引用变量以及类型的对象之前声明。
delegate void MyDel(int x); //其中的MyDel就是委托类型名,类似于类名
注意:委托的类型声明,不需要在类内部声明,因为委托类型和类是同一个级别的。
3. 创建委托对象
委托是引用类型的,因此有引用和对象,就像上图中所示,引用变量存在栈内存中,委托对象存在堆内存中。
MyDel delVar; //委托变量的声明,也就是委托引用
委托对象的创建:
delVar = new MyDel(myIntsObj.methodName); dVar = new Mydel(SClass.staticMethodName); //使用new关键字创建委托对象,同时给委托类型的默认构造函数传一个方法名作为参数。 //这个方法名就是委托对象调用列表中的第一个成员的方法的名字。
提示:在创建委托对象的时候有快捷的语句
delVar = myIntsObj.methodName; dVar = SClass.staticMethodName;
这是因为方法名称和其相对应的委托类型之间有隐式的转换。
图中的Invocation list里面存储的都是一些函数指针。
当然上面的创建对象可以在一条语句上完成:
MyDel delVar = new MyDel(myIntsObj.methodName); MyDel dVar = new Mydel(SClass.staticMethodName);
或者:
MyDel delVar = myIntsObj.methodName; MyDel dVar = SClass.staticMethodName;
4. 委托赋值
由于委托是引用类型的,可以通过给它赋值来改变包含在委托变量中的引用。旧的委托对象会被垃圾回收器回收。
MyDel delVar; delVar = myIntsObj.methodName; . . delVar = SClass.staticMethodName;
注意:这里用到了C#垃圾回收器的知识。
5. 修改委托
事实上,委托是恒定的,委托对象被创建后就不会再改变。任何对委托对象的修改都是创建一个新的委托,同时按照要求修改这个新委托对象的调用列表。
组合委托:
MyDel delA = myIntsObj.methodName; MyDel delB = SClass.staticMethodName; MyDel delC = delA + delB;//组合调用列表
委托增加和删除方法:
MyDel delVar = inst.MyM1;//创建并初始化 delVar += SCL.m3;//增加方法 delVar += X.Act;//增加方法
delVar -= SCL.m3;//从委托移除方法
6. 调用委托
试图调用空的委托对象会抛出异常,所以每次调用委托对象的时候,把委托对象和null进行比较,来判断委托对象的调用列表是否为空。
注意:
委托引用变量没有被初始化前,委托引用是null。委托对象中的调用列表为空,那么委托引用也为null。
调用方法是直接用委托引用,加上相对应的参数:
if(delVar != null) { delVar(55); }
补充的知识点:
1. 当调用带返回值的委托对象时,调用列表中最后一个方法返回的值就是委托调用的返回值,调用列表中其他所有的方法的返回值都会被忽略。只是返回值被忽略,方法的操作还是有效果的(比如对全局变量的修改)。
2. 如果委托有引用参数,参数值会根据调用列表中的一个或多个方法的返回值而改变。在调用委托列表中的下一个方法时,参数的新值(不是初始值)会传给下一个方法。
标签:
原文地址:http://www.cnblogs.com/stemon/p/4431534.html