上周五有同事问了我一个问题: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都可以。 

转载于:https://www.cnblogs.com/itjeff/p/5410445.html

Delegate成员变量和Event的区别相关推荐

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

    package com.zhangxueliang.demo;import org.junit.Test;/** 成员变量和局部变量的区别:* A:在类中的位置不同* 成员变量:类中,方法外* 局部变 ...

  2. 成员变量和类变量的区别:

    成员变量和类变量的区别: 1.两个变量的生命周期不同 成员变量随着对象的创建而存在,随着对象的回收而释放. 静态变量随着类的加载而存在,随着类的消失而消失. 2.调用方式不同 成员变量只能被对象调用. ...

  3. 成员变量与局部变量的区别

    成员变量与局部变量的区别 1.在类中的位置不同 成员变量:在类中方法外面 局部变量:在方法或者代码块中,或者方法的声明上(即在参数列表中) 2.在内存中的位置不同,可以看看Java程序内存的简单分析 ...

  4. Java类定义、成员变量定义、方法定义、成员变量与局部变量的区别

    编程语言的三大发展阶段:面向机器语言.面向过程语言.面向对象语言 : 其中面向对象语言主要体现三个特征:封装性.继承.动态 : 类的定义:类声明和类体.基本格式如下: class 类名{    类体 ...

  5. 7 面向对象(成员变量和局部变量的区别,类作为形式参数的问题,匿名对象,封装,private关键字,this关键字,构造方法,类的初始化过程,static关键字)

    1:成员变量和局部变量的区别(理解) (1)在类中的位置不同 成员变量:类中方法外 局部变量:方法定义中或者方法声明上 (2)在内存中的位置不同 成员变量:在堆中 局部变量:在栈中 (3)生命周期不同 ...

  6. JAVA 成员变量与局部变量的区别

    public class ObjectOrientend5 {int x;//为成员变量,紧跟着类public void show(int a){int y = 0;//这里的a,y都是在方法中,故都 ...

  7. 【笔记】Java中使用变量的规则(使用变量,遵循就近原则)、成员变量和局部变量的区别

    文章目录 一.使用变量的规则 二.成员变量和局部变量的区别 一.使用变量的规则 最终输出的是"小黑正在努力学习" 使用变量,遵循就近原则 例:将上述代码敲一遍 Student部分 ...

  8. Java学习笔记day14(两个引用指向同一对象内存图解、成员变量和局部变量的区别、private关键字、this关键字、构造方法的特点、面向对象标准汽车类练习)

    *1.两个引用指向同一对象内存:  *         例子:Phone.java与Phone_Test.java /** 手机类:* 成员变量:品牌,价格,颜色...* 成员方法:打电话,发短信.. ...

  9. java中成员变量和全局变量的区别_成员变量与全局变量的区别

    全局变量:也叫成员变量,是指在类中定义的变量:它在整个类中都有效 全局变量又可分为:类变量和实例变量 1.类变量:又叫静态变量  用static修饰  它可以直接用类名调用  也可以用对象调用   而 ...

最新文章

  1. mysql命令行批量添加数据_mysql命令行批量插入100条数据命令
  2. 在Java项目用框架(hibernate)的前提下解决sql的union问题
  3. simulink里面pid模块N的参数什么意思?
  4. djangoORM语句
  5. Netty-案例 WebSocket与netty实现长连接案例(代码注释详解)
  6. 安卓系统手机软件_2M不到的安卓神器!有了这五款软件,iphone用户都羡慕
  7. 查看Scala编译的.class文件
  8. u8转完看不到菜单_填制凭证界面上的菜单看不见
  9. datagrid sortname如何定义多列_如何实现一个小说分页的功能
  10. layui select第一次无法选中_Windows 10 无法访问共享的解决办法大全
  11. 如何调整Exadata DB节点文件系统大小
  12. mysql分页查询非常慢_MySQL分页查询慢的原因及解决方案
  13. 港股通接口获取香港交易所上市股票的基本信息
  14. WiFi、GNSS定位服务实战-OneOS位置服务组件(文末有礼品)
  15. 作为IT面试官,我如何考核计算机专业毕业生?作为培训班老师,我又如何提升他们?
  16. SAP案例教程FI财务后台配置
  17. 港联证券|TMT板块全线退潮,这些个股获主力逆市抢筹
  18. 考拉解析网站Android 安卓手机下载视频到手机相册
  19. 【python】一篇文章入门python简单画图
  20. 机房防雷,做到这一点很重要

热门文章

  1. delphi:多态置换原则
  2. 网络工程师常用英文简写
  3. php函数设置默认值,php函数如何设置默认值作为对象?
  4. 包红b2c模块 flutter与原生交互
  5. 网站防火墙探测工具Wafw00f
  6. mfc和mysql连接 dao_用MFC DAO 在VC++6.0进行与数据库的连接,对数据库进行定义和操作,最后断开数据库的连接等各种操作。...
  7. python ctime源码_Python3基础 getatime getctime getmtime 文件的最近访问 + 属性修改 + 内容修改时间...
  8. mysql olap 工具_OLAP分析工具之Presto
  9. python中args和kwargs_Python 函数参数*args和**kwargs
  10. php 输出图片给js,如何在php中利用croppic.js对图片进行剪切并上传