ch01..深入理解C#委托及原理_《没有控件的ASPDONET》

一、委托

设想,如果我们写了一个厨师做菜方法用来做菜,里面有 拿菜、切菜、配菜、炒菜 四个环节,但编写此方法代码的人想让 配菜 这个环节让调用方法的人实现,换句话说,就是想在方法被调用时接收代码 作为参数,在方法中执行这端传进来的代码。

但,怎么为一个方法传 代码 进来呢?当然大家想到了传递接口方式来实现,咱先不讨论接口,因为微软为我们提供了一个叫做 【委托】 的类型。

(一)、委托基础:

1.       先看看代码:

(1).定一个方法:void SayHi(string name){Console.WriteLine(“Hi~”+name+”! ” );}

(2).声明一种委托类型:delegate void DGSayHi(string uName);

(3).创建委托类型对象:DGSayHi dgObj = new DGSayHi(SayHi);//构造函数中传入了方法

(4).执行委托: dgObj(“JamesZou”); //调用委托(奇怪:对象加括号 的方式调用?后面解释。) 输出:Hi~JamesZou!

2.       什么是委托? (1)概念:“C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后调用该委托对象就可以执行委托对象内方法引用指向的方法,而不必在编译时知道将调用哪个方法(如参数为委托类型的方法,也就是提供了为程序回调指定方法的机制)。”-- 引自MSDN
(2)通俗:就是一个能存放很多方法的指针的调用清单(但方法签名必须和委托类型签名一样),你一调用这个清单,那么清单里的所有的指针所对应的方法就会依次被执行。
(3)比方说:有三台机器A、C、D,点一个红色按钮就会运行。操作人员接到指令,要求在接到电话后分别打开AD机器,然后然后工人就在接到电话后,先后打开AD机器。(此例中的 三台机器就是方法,操作员,就可以看成是“委托”啦)

(4)概要图例: DGSayHi dgObj = new DGSayHi(SayHi); dgObj(“James”); //调用委托对象,就会执行委托对象里的方法。

3.       委托有什么用? A.能够帮程序员在需要时,根据条件动态执行多个方法:(接上例代码)

(1)定三个方法: void SayHi(string name){Console.WriteLine(“Hi~”+name ); } void DaZhaoHu(string name){ Console.WriteLine(“你好啊~”+name ); } string OHaUo(string name){ Console.WriteLine(“OHaUo ~”+name ); return “JapHi”;}

(2)创建委托类型对象,并通过构造函数传参方式向委托对象“注册”第一个方法: DGSayHi dgObj = new DGSayHi(SayHi);

(3)继续“注册两个方法”: dgObj+=DaZhaoHu;// (奇怪:对象之间用+=符号来操作?后面解释) //dgObj+=OhaUo;//注释此行代码,因为编译时报错,OhaUo方法签名与委托类型的签名不一致(委托签名无返回值)。

(4)执行委托对象: dgObj(“James”); //执行了此委托中注册的两个方法 输出: Hi~James 你好啊~James

(5)概要图例

B. 委托作为方法参数(回调方法机制)

(1).接上例代码,再定义一个方法: void DoTestDelegateFun(DGSayHi dgObj){dgObj(“钢铁侠”);} (2).调用此方法: DoTestDelegateFun(SayHi);//输出:Hi~钢铁侠(奇怪:竟然直接传方法了?后面解释)

C.委托语法糖

(1).注意到上面有3个地方我们都觉得“奇怪”:         a.调用委托对象dgObj(“JamesZou”);         b.向委托注册方法 dgObj+=DaZhaoHu;

c.将方法作为参数 DoTestDelegateFun(SayHi);

这些用法其实都是FW为我们提供的简便语法(它们有个可爱的名字:语法糖),在编译时由编译器转成完整的代码:         a. dgObj.Invoke(“JamesZou”);         b. dgObj = (DGSayHi) Delegate.Combine(dgObj, new DGSayHi(this.DaZhaoHu));

//Combine方法将第二个参数,添加到dgObj中,并返回委托对象。 c. this.DoTestDelegateFun(new DGSayHi(this.SayHi));

Delegate类、Invoke方法、Combine方法是哪来的呢?

(二)、委托原理

1.delegate 关键字

(1).概念:delegate 关键字用于声明一个引用类型,该引用类型可用于封装命名方法或匿名方法。

(2)编译后生成的的中间代码。  请大家思考一下,关键字是类型吗?不是。那编译器遇到这个关键字做了什么事情?借助【IL反汇编程序】 我们来看一看:

a.开始-程序-如图:

b.打开项目文件夹下的bin\Debug文件夹,找到程序集 CodeForFun.exe,拖入到【IL反汇编程序】界面中便可看到程序集的IL代码: 找到我们定义了委托DGSayHi的类DelegateForFun,发现,里面的 委托类型声明 代码 编译前:delegate string DGSayHi(string uName); 变成了一个类:

单击展开后我们再来看看:

看出什么了? (I).继承了System.MulticastDelegate。 (II).包含了构造方法、BeginInvoke、EndInvoke、Invoke方法。 也就是说此时,delegate代码已经编译成了如下代码: 编译后: class DGSayHi:System.MulticastDelegate  {   public DelegateForFun();

void Invoke(string value);

IAsyncResult BeginInvoke(string value,AsyncCallback callback,Object object);

void EndInvoke(IAsyncResult result);

}

(3)System.MulticastDelegate 类

下面我们来看看借助.Net Reflector工具来查看类库中的 MulticastDelegate 类

public abstract class MulticastDelegate : Delegate

由此我们可以看出继承关系:DGSayHi –> MulticastDelegate–> Delegate

MulticastDelegate类中有3个重要的成员,其中两个继承自 Delegate  :

a.三者的作用:

_methodPtr 里保存的就是 方法指针。

_target 里用来保存方法所在的对象。

_invocationList 其实使用时是个object数组,在注册多个方法时,其他方法就保存在此成员中,而它也就是 委托链 的关键容器。

b.概要图:

图中的委托对象 dgObj 在创建时创建了指向方法 SayHi的指针并保存在 _methodPtr中;_target中保存了SayHi方法所在的类的对象(比如我把这段代码写在窗体里按钮的点击方法中,那么此时 _target就是 SayHi方法所在的窗体对象);_invocationList 中保存了追加的两个方法的指针,但这两个方法指针都是分别被装在 MuticastDelegate对象中。

  转载请注明出处:ch01.深入理解C#委托及原理 开智网http://www.oumind.com

 

ch01.深入理解C#委托及原理(转)的更多相关文章

  1. js的事件的三个阶段,事件委托的原理

    DOM2级事件规定的事件流的三个阶段:捕获,目标,冒泡(IE8以及更早版本不支持DOM事件流); 事件流: IE:IE事件流是事件冒泡流  Netscape事件流是事件捕获流 IE事件流 叫做事件冒泡 ...

  2. Atitit 深入理解耦合Coupling的原理与attilax总结

    Atitit 深入理解耦合Coupling的原理与attilax总结     耦合是指两个或两个以上的电路元件或电网络等的输入与输出之间存在紧密配合与相互影响,并通过相互作用从一侧向另一侧传输能量的现 ...

  3. [diango]理解django视图工作原理

    前言:正确理解django视图view,模型model,模板的概念及其之间的关联关系,才能快速学习并上手使用django制作网页 本文主要讲解自己在学习django后对视图view的理解 在进入正文之 ...

  4. 《深入理解OSGi:Equinox原理、应用与最佳实践》笔记_1_运行最简单的bundlehelloworld

    <深入理解OSGi:Equinox原理.应用与最佳实践>笔记_1_运行最简单的bundlehelloworld 买了周大大的OSGI的书看 先前完全没有基础 就靠这本书看看学学 顺便记一些 ...

  5. Java进阶(七)正确理解Thread Local的原理与适用场景

    原创文章,始自发作者个人博客,转载请务必将下面这段话置于文章开头处(保留超链接). 本文转发自技术世界,原文链接 http://www.jasongj.com/java/threadlocal/ Th ...

  6. 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)

    ♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ...

  7. 彻底理解MapReduce shuffle过程原理

    彻底理解MapReduce shuffle过程原理 MapReduce的Shuffle过程介绍 Shuffle的本义是洗牌.混洗,把一组有一定规则的数据尽量转换成一组无规则的数据,越随机越好.MapR ...

  8. 【转载】深入理解PHP Opcode缓存原理

    转载地址:深入理解PHP Opcode缓存原理 什么是opcode缓存? 当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode).O ...

  9. 理解java容器底层原理--手动实现HashMap

    HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...

随机推荐

  1. wpa_supplicant使用笔记-wpa_cli iwconfig

    还在搞8634,看不到头了..唉.wireless_tools的缺点是不支持WPA认证,所以有必要把wpa_supplicant也移植过来.无线 网卡是基于zydas芯片的,正好可以在网上搜到wpa_ ...

  2. margin:-75px的理解及妙用——纯CSS制作水平/垂直都居中短边为50px/长边为150px的红色十字架

    有这么一个题目: 使用重构的方式制作出一个如下图的水平.垂直都居中短边为50px,长边为150px的红色十字架. 要求只使用2个div完成 答案: <!DOCTYPE html PUBLIC & ...

  3. UVA 10820 - Send a Table 数论 (欧拉函数)

    Send a Table Input: Standard Input Output: Standard Output When participating in programming contest ...

  4. LINUX curl GET 掉参数解决办法

    LINUX curl GET 掉参数解决方法 url 为 http://mywebsite.com/index.php?a=1&b=2&c=3web形式下访问url地址,使用 $_GE ...

  5. JSON字符串与JSON对象的区别及转换

    JSON对象是直接可以使用JQuery操作的格式,和js中的对象一样,可以用对象(类名)点出属性(方法). JSON字符串仅仅只是一个字符串,一个整体,不截取的话没办法取出其中存储的数据,不能直接使用 ...

  6. 【动态页面】(二)Java反射

    Java的反射机制是Java语言非常重要的一个特性.先从Sun官网上看一下官网是怎样定义反射机制的. 大致翻译一下,翻译的可能不是非常准确. 反射(Reflection)是Java程序设计语言的一个特 ...

  7. python-增删改查

    ###增删改查 names = ["zhangding","wangxu","wudong","cheng"] #增 n ...

  8. 提升升级 强制更新 Download

    Activity和广播 /** 下载APK细节 1.点击升级后对话框不消失,再次点击时不能重复下载 2.下载过程中退出APP,下次进入应用后要重新下载(因为可能不完整) 3.下载过程中退出APP(或下 ...

  9. android TimerTask 的简单应用,以及java.lang.IllegalStateException: TimerTask is scheduled already错误的解决方法【转】

    Android应用开发中常常会用到定时器,不可避免的需要用到 TimerTask 定时器任务这个类下面简单的一个示例演示了如何使用TimerTask这个示例演示了3秒未有触屏事件发生则锁屏(只是设置下 ...

  10. entity 实体模型timeout设置

    public Entities(): base("name=Entities") { var adapter = (IObjectContextAdapter)this; var ...