上周五有同事问了我一个问题:Delegate和Event有什么区别?具体来说在设计一个类的时候,声明一个事件(Event)和声明一个Delegate类型的成员变量有啥区别。
 
我的第一反应是没啥区别,虽然从语法看起来不一样,但从代码希望达成的效果来看是一致的,本质都是回调函数。当然区别是肯定有的,我能给我的理由是两个:首先从与COM交互操作时,event对应COM接口中的事件;其次VS的编译环境对定义event提供了更加便捷的支持,可以为其自动生成回调函数的框架。
 
翻了翻MSDN,并没有直接描述两者的不同,不过存了个心眼,抽空做了一个小例子,还是发现了一些微妙的不同。
 
 
 
简单描述一下,首先定义一个最简单的类,就包括一个公共的委托类型的成员变量和一个公共事件,以及相应的触发函数。
 
        #region class CTest
        private class CTest
        {
            public EventHandler TestDelegate;
            public event EventHandler TestEvent;
 
            public void RaiseDelegate()
            {
                if (TestDelegate != null)
                    TestDelegate(this, EventArgs.Empty);
            }
 
            public void RaiseEvent()
            {
                if (TestEvent != null)
                    TestEvent(this, EventArgs.Empty);
            }
        }
 
        #endregion // End of class CTest
 
 
 
然后写一个窗口类,上面放两个按钮,一个按钮(btnRaiseDelegate)调用RaiseDelegate方法,一个按钮(btnRaiseEvent)调用RaiseEvent方法。并且在窗口类中定义两个回调函数,当这两个回调函数被调用时,分别在窗口中的ListBox(lstLog)中添加一行,说明到底是Delegate被触发,还是Event被触发。常规写法,很容易理解。
 
        private void TestDelegateFunc(Object sender, EventArgs e)
        {
            Debug.Assert(lstLog != null);
            lstLog.Items.Insert(0,String.Format("Delegate is called at [{0}]",DateTime.Now));
        }
 
        private void TestEventFunc(Object sender, EventArgs e)
        {
            Debug.Assert(lstLog != null);
            lstLog.Items.Insert(0, String.Format("Event is called at [{0}]", DateTime.Now));
        }
 
        private void btnRaiseDelegate_Click(object sender, EventArgs e)
        {
            Debug.Assert(m_oTest != null);
            m_oTest.RaiseDelegate();
        }
 
        private void btnRaiseEvent_Click(object sender, EventArgs e)
        {
            Debug.Assert(m_oTest != null);
            m_oTest.RaiseEvent();
        }
 
 
 
在订阅event和给Delegate赋值的时候发现了问题,Delegate赋值可以支持“=”操作符和“+=”操作符(也就是Delegate.Combine方法),而event只能够通过“+=”方式赋值。当对event使用“=”操作符时,提示错误“The event ‘DelegateAndEvent.FTest.CTest.TestEvent’ can only appear on the left side of += or -= (except whe used from within the type ‘DelegateAndEvent.FTest.Ctest’)”。嘿嘿,最根本的不同可能是这样的,event这个关键字对Delegate类型的成员变量追加了一种限制,禁用了赋值操作符,只能通过“+=”和“-=”修改Delegate的内容。那结果上有什么不同呢,让我们继续看下去,在窗口的构造函数中,完成CTest实例初始化工作。
 
        private CTest m_oTest = null;
 
        public FTest()
        {
            InitializeComponent();
 
            m_oTest = new CTest();
            Debug.Assert(m_oTest != null);
 
            m_oTest.TestDelegate += new EventHandler(TestDelegateFunc);
            m_oTest.TestDelegate = new EventHandler(TestDelegateFunc);
 
            m_oTest.TestEvent += new EventHandler(TestEventFunc);
            m_oTest.TestEvent += new EventHandler(TestEventFunc);
        }
 
 
 
运行测试程序,单击btnTestDelegate,ListBox中增加了一行输出,而单击btnTestEvent,ListBox中增加了两行输出。如图:
 
 
 
示例程序窗口
 
 
 
所以对于Delegate类型而言,赋值操作符是改写了内部全部内容,而“+=”和“-=”操作符只能够在原有基础上增加或者减少内容。event就像property一样,它是一种特殊的封装形式,对成员变量进行了一定的保护,限制了外界修改成员变量的部分内容。那么为什么要增加这样的限制呢,推测event更多的是考虑多人订阅的情况,不允许一个订阅者去修改其它订阅者的内容,如果支持赋值操作的话,那么最后一个订阅者有可能清除之前所有订阅信息。
 
因此可以给出这样一个使用建议:如果一次回调需要通知多个订阅者的话,那么采用event是一个很好的安全策略;如果任何时候只有一个订阅者的话,那么无论用delegate还是event都可以。 

Delegate成员变量和Event的区别的更多相关文章

  1. 《java入门第一季》之面向对象面试题(成员变量与局部变量的区别)

    /* 成员变量和局部变量的区别? A:在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B:在内存中的位置不同 成员变量:在堆内存 局部变量:在栈内存 C:生命周期不同 ...

  2. java 成员变量和局部变量的区别

    将对象的存储在数组中会报错 public static void main(String[] args) { ArrayList<Goods> arrayList = new ArrayL ...

  3. iOS 成员变量和属性的区别

    一. 成员变量 1.成员变量的作用范围: @public:在任何地方都能直接访问对象的成员变量 @private:只能在当前类的对象方法中直接访问,如果子类要访问需要调用父类的get/set方法 @p ...

  4. Java中成员变量和局部变量的区别

    java面向对象过程中,最基本的两类变量就是成员变量和局部变量 成员变量是写在类中并且写在方法外部,一般写在每个类的头部,用于初始化或者方法操作,作用域是整个类被实例化到被销毁,中间变量都可以被外部方 ...

  5. 【Java基础】成员变量和局部变量的区别

    在类中的位置不同 成员变量:在类内部方法外部 局部变量:在方法体内部定义的或者方法的参数中定义的在内存中的位置不同 成员变量:在堆内存,有初始化值,byte,short,int,long->0, ...

  6. java当中成员变量和局部变量的区别

    1:成员变量定义在类中,整个类中都可以访问.2:局部变量定义在函数,语句,局部代码块中,只在所属的区域有效.3:成员变量存在于堆内存的对象中.4:局部变量存在于栈内存的方法中.5:成员变量随着对象的创 ...

  7. JAVA:成员变量和局部变量的区别

    1.作用于不同: 局部变量的作用域仅限于定义它的方法 成员变量的作用域在整个类的内部都是可见的 2.初始值不同 JAVA会给成员变量一个初始值 JAVA不会给局部变量赋予初始值 3.在同一个方法中,不 ...

  8. Java成员变量与局部变量的区别

    从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数:成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所 ...

  9. Java 成员变量和属性的区别

    例一: 一个Student pojo类: public class Student{ private String name; private int age; public String getNa ...

随机推荐

  1. bootstarp modal自己主动调整宽度的JS代码

    $('#ajaxPage').modal('show').css({ width: 'auto', 'margin-left': function () { return -($(this).widt ...

  2. PHP读取Excel里的文件

    下载phpExcelReader  http://sourceforge.net/projects/phpexcelreader 解压后得到以下这些文件 jxlrwtest.xls这个excel文件有 ...

  3. c++11多线程简介

    C++11开始支持多线程编程,之前多线程编程都需要系统的支持,在不同的系统下创建线程需要不同的API如pthread_create(),Createthread(),beginthread()等,使用 ...

  4. 用SourceTree轻巧Git项目图解

    用SourceTree轻松Git项目图解 这篇文档的目的是:让使用Git更轻松. 看完这篇文档你能做到的是: 1.简单的用Git管理项目. 2.怎样既要开发又要处理发布出去的版本bug情况. Sour ...

  5. 【cocos2d-x】尝鲜 Cocos Code IDE(不断更新)

    Cocos Code IDE 是一个基于 Eclipse 的跨平台 IDE ,专门为 cocos2d lua & js 开发者准备,通过此工具.你能够方便的创建游戏project.编写而且调试 ...

  6. 解决IIS7中出现An error occurred on the server when processing the URL错误提示的方法

    在IIS7上配置一个asp程序,出现了一个错如提示: An error occurred on the server when processing the URL. Please contact t ...

  7. atitit.(设计模式1)--—职责链(chain of responsibility)最佳实践O7 转换日期

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 能够选择的模式: 表格模式,责任链模式 1 3 ...

  8. w3wp占用CPU过高

    w3wp占用CPU过高 在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔CPU会跑满,虽然之前使用过WinDbg解决过两次问题但人的记忆是不可靠的,今天处理同样问题的时候还是遇到了一 ...

  9. Android Property Animation 物业动画

    效果图:   Property Animation介绍: 出生在sdk3.0,是利用了View所拥有的属性,进行一系列的操作. 比方一个View有什么样的setAbc的属性,那么理论上就能够设置它. ...

  10. 用户配置文件(passwd/shadow)

    管理员工作,这是管理帐户的一个非常重要的组成部分.由于整个系统你在的管理, 和所有一般 郄用户帐号申请.所有的,他们会通过你的工作需要得到援助.所以,你需要知道他将如何管理服务器主机挈朋友 帐号! 在 ...