C#委托与事件的本质区别

  从定义上说,委托被编译器编译成一个类,所以它可以像类一样在任何地方定义,而事件被编译成一个委托类型的私有字段和两个公有add 和 remove 方法(有点类似于属性的定义)不过这两个方法都有一个参数,这个参数就是委托,所以,它只能定义在一个类里面。

   从定义可知,委托是要是需要实例化的,它4个方法:一个构造器,Invoke,BeginInvoke和EndInvoke。构造器有两个参数分别是:一个对象引用,另一个是引用回调方法的一个IntPtr。然而实例化委托的代码的参数只是一个方法的引用。但这不是问题,编译器明白这其中的一切会获取对应的参数。然而事件是不需要实例化的因为他只是一个字段和两个方法,只是类的一些成员,但是可以初始化,通过一些赋值操作!

    实例化委托时,定义他参数的方法的参数及返回类型必须符合委托的Invoke参数及返回类型,而事件被定义后,它可以通过方法所在类的对象调用add方法来添加一个委托和remove方法来移除一个委托!而两个方法的结果是返回一个委托引用并赋值给事件定义生成的私有委托字段,如果是多次调用就返回一个委托列表头的引用。而传入的这个参数即是由要触发的方法而封装的委托。(参数为什么是委托而不直接传入一个方法引用呢,这样效率不是更高吗)因为委托是调用回调方法的一种类型安全的方式。通过add方法即是订阅了一个事件,然后就是触发事件了,即通过点击按钮等输入操作即可触发事件,然后调用私有的委托变量,然后即像调用委托一样,调用他的Invoke方法即引用定义的方法的地址来执行该方法,然后这个事件就结束了。

  总结:事件的订阅分两个阶段:首先是传入的参数(即委托)的实例化,相当于委托的实例化,调用该委托的构造函数(一个对象引用,一个IntPtr类型的回调方法的引用),其次就是委托链(也即多播委托)的构建过程,第一次订阅是用一个null和传入的委托的Combine,此时直接返回传入的委托地址,如果第二次订阅就会构造一个新的委托对象,_invocationList字段被初始化为一个委托对象数组,引用两个委托地址,最后返回这个新建的对象地址,以后依此类推。

  接下来就是事件的触发阶段了,通过鼠标单击或动态用代码去实现,其本质只有一个步骤即委托的调用,如果只有一个委托,直接调用Invoke方法,如果有多个委托,即发现_invocationList不为null,会循环调用数组里的所有元素,每个元素的实现即为只有一个委托时调用的Invoke方法。

    简而言之,即事件分为两个阶段一个是委托的实例化(对应事件订阅),一个是委托的调用(对应事件触发)。

猜你喜欢

转载自www.cnblogs.com/-831/p/11248868.html