本来按照进度应该学习事件了,可总觉得应该委托在前,事件在后,才好理解。

委托是一个类,它提供了回调函数机制,而且是类型安全的。使用委托可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,提高了程序的可扩展性。


使用委托

老规矩,先上个例子:

结果:

几点说明:

  1. 使用关键字delegate声明委托。委托是类型安全的,定义时其返回值类型、参数个数及参数类型要和想要调用的方法兼容。
  2. 在这个例子中,通过Introduce方法获取对delegateIntroduce委托对象的引用。委托对象相当于方法的包装器,使方法能通过包装器进行间接回调。
  3. 委托即允许调用静态方法(如①②),还允许调用实例方法(③)。
  4. 将一个方法绑定到委托时,允许引用类型的协变性和逆变性。(ps:陌生的词汇…)
  • 协变性:方法能返回委托类型的派生类型;
  • 逆变性:方法获取的参数可以是委托类型参数的基类。

注意:这两点只限于引用类型,不能用于值类型或者void。

编译结果

  1. 委托实际上会编译成一个类,包含四个方法:.ctor, Invoke, BeginInvoke, EndInvoke。
  2. 所有的委托都会自动继承类System.MulticastDelegate。 MulticastDelegate又继承自Delegate。
  3. MulticastDelegate类提供了三个公共字段:

名称

类型

说明

_target

System.Object

当委托调用静态方法时,该字段为null。当委托调用实例方法时,表示回调方法要操作的对象。

_methodPtr

System.InPtr

标识要回调的方法

_invocationList

System.Object

通常为Null,在委托链时可以引用一个委托数组

4.    Delegate类提供了两个只读属性:

  • Target   :返回字段_target的值
  • Method :将字段_methodPtr的值转换为MethodInfo并返回。

例如:

结果:

委托链

委托链是由委托对象构成的一个集合。这样就可以将多个方法绑定到同一个委托,调用这个委托的时候会依次调用其所绑定的方法。

接着上面的例子,我们修改Main方法的调用:

结果:

构造委托链时,用到了两个静态方法:

  • Delegate.Combine(d1,d2) :将委托添加到委托链中。其间_invocationList字段会初始化为一个委托对象数组。上面例子构造完成后该_invocationList[0]被初始化为di1所引用的委托,以此类推。在执行时,发现_invocatonList字段不为空,则会遍历数组元素,顺序调用每个委托包装的方法。
  • Delegate.Remove (d1,d2) :从d1的委托数组中字段中查找_target和_methodPtr字段与d2匹配的委托,找到后移除。即使匹配记录有多个,每次也只移除一个。

另外,MulticastDelegate类还提供了GetInvocationList()方法,来查看委托链中的委托数组。例如我们将调用委托的Introduce方法略作修改:

结果:

+=、-=

C#为委托的+=和-=操作符进行了重载,来简化语法。

执行结果相同。查看IL代码就会发现他们实际调用的是Combine和Remove方法。


THE END.

下次再碰上笔试或者面试的就不用紧张兮兮的了,可以洋洋洒洒的说一通了。

你也许喜欢:跟小静读CLR via C#(00)-开篇及目录

跟小静学CLR via C#(12)-委托Delegate相关推荐

  1. 跟小静读CLR via C#-开篇及目录

    最近正在拜读Jeffrey大师的.NET巨作-<CLR via C#>.好书就像一杯茶,需要静下心来慢慢品.在写笔记的过程中,也加入了自己的思考:在和园友们的交流中,理解也不断的加深. 目 ...

  2. 跟小静读CLR via C#(02)-基元类型、引用类型、值类型

    跟小静读CLR via C#(02)-基元类型.引用类型.值类型 一. 基元类型 编译器能够直接支持的数据类型叫做基元类型.例如int, string等.基元类型和.NET框架类库FCL存在着直接的映 ...

  3. 跟小静读CLR via C#(05)- 访问限定、数据成员

    跟小静读CLR via C#(05)- 访问限定.数据成员 今天跟大家分享一下关于访问限定和数据成员的知识.主要包括以下两点: Abstract, sealed, virtual, new, over ...

  4. 跟小静读CLR via C#(06)- 构造器

    跟小静读CLR via C#(06)- 构造器 最近忙着看新还珠,好几天不学习了.玩物丧志啊,罪过罪过. 今天总结的是类构造器的知识,其实这方面的文章蛮多的,可还是觉得亲自写一下对自己的思考和认识会有 ...

  5. 跟小静学MVC3[01]--创建第一个MVC3项目

    [前言]从今天开始,小静要学习Pro ASP.NET MVC3 Framework这本经典大作了,我是下载的电子版学习的.在这里只是用作学习的记录,便于以后查阅,也为了督促自己坚持下去.不用于任何商业 ...

  6. 跟小静读CLR via C#(16)--泛型

    泛型就像是一个模板,常常定义一些通用的算法,具体调用时再替换成实际的数据类型,提高了代码的可重用性. 一.初识泛型 1. 简单实例 以最常用的FCL中的泛型List<T >为例: stat ...

  7. 跟小静读CLR via C#(10)-参数

    最近几天学了参数,其实对于参数本不陌生,从上学学C语言基础的时候就学过了.不过细心学下来,还是收获了一些. 一. 命名参数.可选参数 命名参数和可选参数是在Visual C#2010中引入的新特性. ...

  8. 跟小静读CLR via C#(18)——Enum

    1. Enum定义 枚举类型是经常用的一种"名称/值"的形式,例如: public enum FeedbackStatus      {          New,         ...

  9. 小余学调度:学习记录(2021年12月)

    小余学调度系列文章,记录小余同学入职电力调度员一路的学习记录,由于工作性质,在这个系列,只写能公开的知识点,不涉及机密. 提示:专栏解锁后,可以查看该专栏所有文章 文章目录 一.对母线充电时,不能带电 ...

最新文章

  1. Rocksdb 的优秀代码(一) -- 工业级分桶算法实现分位数p50,p99,p9999
  2. 工业互联网的十大关键传感器
  3. thinkphp scws mysql_thinkphp buildHtml 函数实现网站静态化
  4. 5月19-20日WebRTCon 2018 梳理全球WebRTC技术实践与案例
  5. VC++ 非托管代码 托管代码
  6. Memcached原理与应用
  7. spring component-scan配置扫描多个包
  8. 如何在Scala中使用条件表达式
  9. linux ldap配置详解
  10. 【PRML 学习笔记】第一章 - 介绍 (Introduction)
  11. 深度linux清理空间,怎样清理内存缓存
  12. 飞鱼星路由器端口映射/端口转发的设置步骤及注意事项
  13. SiT9005:1 -141MHz单端扩频振荡器SSXO
  14. 2019年安徽大学ACM/ICPC实验室新生赛题解
  15. 搜索引擎相关站点收集
  16. Policy Evaluation收敛性、炼丹与数学家
  17. 提高访问国外网站速度
  18. js简繁转换,两种实现方式,妥妥的~
  19. 字符串匹配KMP算法及其时间复杂度分析
  20. 2.9寸墨水屏制作互联网时钟填坑手记

热门文章

  1. 基于CSDN完成TEASOFT的MOOC编辑整理
  2. 相机成像与校正原理:将外部世界进行降维
  3. Carmaer 500W 逆变器初步测试
  4. FZ35恒流电子负载检测测试
  5. 直播预告 | 全国大学生智能汽车竞赛全向行进组——基础培训
  6. python中pandas格式_Python学习笔记之数据分析中Pandas常用知识
  7. xml信息管理系统_WPF信息管理系统项目实战教程二:使用XAML实现页面布局
  8. oracle中DBWR全称,Oracle基本术语大全
  9. nginx配置静态资源html,通过nginx服务器访问静态资源(示例代码)
  10. sqlite3 增删更改查询 callback使用