码迷,mamicode.com
首页 > 其他好文 > 详细

事件和委托(Event vs. Delegate)-事件阉割版的Delegate

时间:2015-11-06 10:53:58      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:

引言

关于事件和委托的文章看过很多,但总是记不完整。尤其是在给别人讲解的时候总是很零碎,所以在此整理一下,也供大家参考,很请大家不吝赐教。

本文从一个子类如何触发基类的事件(Event),引出事件和委托的共性和区别。再简单分析下背后原因,深层原因也给大家提供了部分参考资料。欢迎大家留言讨论。

技术分享

 

问题

“如果我想在子类里触发父类的事件(Event)应该如何实现?”(可以先自己做下或者想下,再继续看您的做法是否也曾有我碰到技术误区)

 

问题分解为两步:

  1. 父类定义了一个事件(Event)
  2. 子类触发父类中定义的这个事件(Event)

最初的想法是:

class BaseClass
    {
        public delegate void CompletedEventHandler();

        public event CompletedEventHandler WorkCompleted;

        private void DoSomeThingInBase()
        {
            //do something then to notify other class
            if (WorkCompleted != null)
            {
                WorkCompleted();
            }
        }


    }

    class subClass : BaseClass
    {
        private void DoSomeThingInSub()
        {
            //do something then to notify other class
            if (WorkCompleted != null)
            {
                WorkCompleted();
            }
        }
    }

您认为上面的代码会如愿以偿吗?

我这么一问大家应该就开始怀疑啦。没错,这种实现这停留在想法里实际上是行不通的,编译器会给出如下的错误提示:

The event ‘BaseClass.WorkCompleted‘ can only appear on the left hand side of += or -= (except when used from within the type ‘BaseClass‘)

问题的解决

我给出我的答案(希望大家也能给出更好的版本):

class BaseClass
    {
        public delegate void CompletedEventHandler();

        public event CompletedEventHandler WorkCompleted;

        private void DoSomeThingInBase()
        {
            //do something then to notify other class
            RaiseCompletedEvent();
        }

        protected void RaiseCompletedEvent()
        {
            if (WorkCompleted != null)
            {
                WorkCompleted();
            }
        }
    }

     class subClass : BaseClass
    {
        private void DoSomeThingInSub()
        {
            //do something then to notify other class
            RaiseCompletedEvent();
        }
    }

问题解释

为什么会出现刚才的问题呢?

其实这个问题的换一个问法,您或许会直接答出来?那就是“事件和委托的区别和联系是什么?”

我也计划从这个角度来解释这个问题:

 

先一句话解释下编译器报错的原因

事件是一种特殊的委托,或者说是受限制的委托,是委托一种特殊应用,只能施加+=,-=操作符。二者本质上是一个东西。

问题挖掘

从委托说起:

如何定义委托?

delegate + function signature // delegate相当于class关键字, function name相当于定义的委托类型.

delegate void Action();

如何创建委托实例?

Action action;

事件是怎样定义和实例化的?

delegate void ActionHandler(object sender, EventArgs args);//先定义委托类型
event ActionHandler ActionEvent;//定义事件实例

对头,事件的定义和委托的定义如出一辙,这也再次从形式上证实了“事件和委托”的一致性。

但是,事件和委托还是有个重要的区别。

事件Vs. 委托

编译成创建一个私有的委托示例, 和施加在其上的add, remove方法.

为说明差异,在示例代码中加入了一个Delegate来类比,代码如下:

class BaseClass
    {
        public delegate void CompletedEventHandler();

        public event CompletedEventHandler WorkCompleted;

        public CompletedEventHandler WorkCompletedDelegate;


        private void DoSomeThingInBase()
        {
            //do something then to notify other class
            RaiseCompletedEvent();

            if (WorkCompletedDelegate != null)
            {
                WorkCompletedDelegate();
            }
        }

        protected void RaiseCompletedEvent()
        {
            if (WorkCompleted != null)
            {
                WorkCompleted();
            }
        }

        
    }

    class SubClass : BaseClass
    {
        private void DoSomeThingInSub()
        {
            //do something then to notify other class
            RaiseCompletedEvent();

            if (WorkCompletedDelegate != null)//不会像事件那样在编译时报错
            {
                WorkCompletedDelegate();
            }
        }
    }

 

ILDASM 查看编译后的结构,可以看出事件被单独赋予了两个方法(实际上就是因为编译器已经对其进行了阉割,不让其他类直接Invoke事件,但delegate是健全的)

技术分享

他山之石

委托和事件支持静态方法和成员方法, delegate(void * pthis, f_ptr), 支持静态返方法时, pthis传null.支持成员方法时, pthis传被通知的对象.

委托对象里的三个重要字段是, pthis, f_ptr, pnext, 也就是被通知对象引用, 函数指针/地址, 委托链表的下一个委托节点.

 

源码下载

下载

总结

delegate关键字类比于class关键字, 定义的是一种委托类型,然后再创建委托实例.

创建委托实例时, 用event关键字来修饰就变成了创建一个事件. 也就是事件是一种特殊的委托.

委托常用来表达回调,事件表达外发的接口

(事件是一个阉割版的delegate,只能对其进行+=,-=的操作,不能出去偷情(被别人Invoke 他/她),不知我的理解是否准确,还请各位路过的大侠赐教)

 

 

参考

事件与委托的联系和区别(文章简短但是内容实在)

C#:委托和自定义事件(基础内容)

C#综合揭秘——深入分析委托与事件(内容颇多,涉及面较宽)

初识Ildasm.exe——IL反编译的实用工具

事件和委托(Event vs. Delegate)-事件阉割版的Delegate

标签:

原文地址:http://www.cnblogs.com/HQFZ/p/4941594.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!