委托与事件
委托:
使用委托我们可以将方法以参数的形式进行传递,委托可以理解为一个指向方法的指针。
事件:
事件只能在声明它的类型的内部进行调用,在外部只能对事件进行注册和注销自己注册的事件,即只能进行+=和-=的操作
委托和事件的区别:
委托是一种类型,它可以在类级别进行声明(即可以直接在命名空间进行声明),而事件是一个对象,只能类型的内部进行声明,其实事件是一个委托的实例,是一个特殊的,进行了功能限制的委托。
事件的组成:
事件的内部其实是由一个私有的委托和一个add_XXX和remove_XXX方法组成的,如下所示,定义了一个委托和对应的事件
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180524140-2073527160.png)
经过反编译之后,可以看到其内部的组成就是一个私有的MyDelete类型的委托MyEvent和add_MyEvent与remove_MyEvent两个方法,如图:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180524843-1423627397.png)
事件的+=与-=操作:
事件的+=和-=操作实际上是调用了事件中的add_XXX方法与remove_XXX方法,对时间中的委托进行合并与移除,如MyEvent事件中调用+=操作,实际上是调用了add_MyEvent方法,在这个方法中对事件中的委托进行了合并操作(调用Delegate.Combine方法)
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180525437-1991881755.png)
委托的声明与使用:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180525859-328713978.png)
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180526921-827103120.png)
委托的继承结构与组成:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180527468-2011662642.png)
委托的==比较:
两个相同类型的委托进行比较时会对委托中参数列表进行对比,只有两个委托的类型与方法列表都相同时,两个委托进行==操作时才会返回True,==比较最后还是调用了Equals方法,如图所示:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180527968-879890352.png)
委托是引用类型么?
从委托继承层次结构,可以看出委托是一种引用类型,但是委托的实例进行+=和-=操作并不会影响另一个指向过它的委托实例,如下代码所示。
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180528499-182710691.png)
1、 从内存的角度来看,初始情况下myDelegate1与myDelegate2在栈中的地址和堆中的地址是相同的,图如图所示:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180528999-1590989878.png)
当对myDelegate1进行+=操作时,myDelegate1在堆中的地址就发生了变化,myDelegate2对象的地址不变,如图:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180529562-1100251109.png)
所以当再次调用myDelegate2这个委托时,它还是调用原来的那个方法列表中的方法,并不会受到myDelegate1的影响。
2、从源代码的角度来看,上述源代码编译之后实际生成的代码如下所示:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180530109-484007321.png)
委托的+=操作最后是调用了Delegate的Combine方法,而Combine方法中又调用了CombineImpl方法,
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180530765-551160808.png)
而CombineImpl方法是一个虚方法,它的具体实现由Delegate的子类MulticastDelegate来重写,在CombineImpl方法中最终调用了NewMulticastDelegate这个方法返回了合并后的委托对象,
CombineImpl方法片段如图:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180531374-197741041.png)
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180531827-1169415723.png)
NewMulticastDelegate的重载方法:
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180532609-2068724152.png)
可以在这个方法中看到最后返回的委托对象已经不再指向原来的委托,已经是一个全新的委托对象了,所以它并没有改变myDelegate1这个委托变量的实际堆中的对象,而是指向了另一个委托实例对象,由此可知+=与-=操作不会影响指向同一个委托对象的多个委托变量。
![](https://images2015.cnblogs.com/blog/846715/201605/846715-20160508180533077-1083952139.png)
作者: 陌上荼靡