委托是什么?
(1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。
(2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象。
既然委托是一种类型,那么它存储的是什么数据?
我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。
委托类型的定义
委托是类型,就好像类是类型一样。与类一样,委托类型必须在被用来创建变量以及类型对象之前声明。
delegate void MyDel(int x);
委托类型声明:
(1) 以deleagate关键字开头。
(2)返回类型+委托类型名+参数列表。
3. 声明委托变量
MyDel del1,del2;
初始化委托变量
(1) 使用new运算符
new运算符的操作数的组成如下:
1 | del1 = new MyDel( myInstObj.MyM1 ); |
方法可以是实例方法或静态方法
(2)使用快捷语法
快键语法,它仅由方法说明符构成。之所以能这样,是因为在方法名称和其相应的委托类型之间有隐式转换。
1 | del1 = myInstObj.MyM1; |
赋值委托
由于委托是引用类型,我们可以通过给它赋值来改变包含在委托变量中的方法地址引用。旧的引用会被垃圾回收器回收。
1 | MyDel del; |
组合委托
委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表是两个操作数的委托调用列表的副本的连接。
委托是恒定的,操作数委托创建后不会被改变。委托组合拷贝的是操作数的副本。
1 | MyDel del1 = myObj.MyMethod; |
委托加减运算
可以使用+=运算符,为委托新增方法。
同样可以使用-=运算符,为委托移除方法。
1 | MyDel del = myObj.MyMethod; |
委托调用
委托调用跟方法调用类似。委托调用后,调用列表的每个方法将会被执行。
在调用委托前,应判断委托是否为空。调用空委托会抛出异常。
1 | if(null != del) |
匿名方法
匿名方法是在初始化委托时内联声明的方法。
基本结构:
1 | deleage( 参数 ) { 语句块 } |
例如:
1 | delegate int MyDel (int x); //定义一个委托 |
从上面我们可以看到,匿名方法是不会显示声明返回值的。
Lambda表达式
Lambda表达式主要用来简化匿名方法的语法。在匿名方法中,delegate关键字有点多余,因为编译器已经知道我们将方法赋值给委托。通过几个简单步骤,我们就可以将匿名方法转换为Lambda表达式:
1 | MyDel del = delegate( int x) { return x; };//匿名方法 |
简单使用
1 | class Program |
注意
使用new初始化委托的时候必须包含参数,参数可以是委托实例,方法,Lambda表达式。
委托是和类一样是一种用户自定义类型:
delegate void MyDel(int x);
很容易把委托MyDel当成一个方法或者属性。
private MyDel _myDel;
这才是一个委托类型的属性
一个委托类型作为类属性的时候,使用+=之前不用进行初始化(不用new或者=进行赋值),但是作为方法内一个变量的时候,必须进行初始化。
1 | private delegate void MyDel(string text); |
事件
1 | public delegate void MyDel(string text); |
类中有一个委托类型的属性。可以这样使用
1 | MyClass myClass=new MyClass(); |
可以为委托增加多个方法
1 | MyClass myClass=new MyClass(); |
因为要在委托上增加方法,声明为public,但是如果一不小心使用了=进行重新赋值(特别是当委托属性是static的时候),就会造成意向不到的结果。为了避免这一情况,使用private修饰委托属性,公开一个方法在委托属性上增加方法。
1 | class MyClass |
事件是一种特殊的委托的实例,或者说是受限制的委托,是委托一种特殊应用,在类的外部只能施加+=,-=操作符,二者本质上是一个东西。
event MyDel _myDel; // 编译成创建一个私有的委托示例, 和施加在其上的add, remove方法.
event只允许用add, remove方法来操作,这导致了它不允许在类的外部被直接触发,只能在类的内部适合的时机触发。委托可以在外部被触发,但是别这么用。
使用中,委托常用来表达回调,事件表达外发的接口。
委托和事件支持静态方法和成员方法, delegate(void * pthis, f_ptr), 支持静态返方法时, pthis传null.支持成员方法时, pthis传被通知的对象.
委托对象里的三个重要字段是, pthis, f_ptr, pnext, 也就是被通知对象引用, 函数指针/地址, 委托链表的下一个委托节点.
1 | private MyDel _myDel;//委托 |
事件不能在类的外部直接调用,只能通过暴露的方法进行间接触发。