首先声明,我是一个菜鸟。一下文章中出现技术误导情况盖不负责

引言:

上一个专题已和大家分享了我懂得的——C#中为什么须要委托,专题中简略介绍了下委托是什么以及委托简略的应用的,在这个专题中将对委托做进一步的介绍的,本专题主要对委实质和委托链停止讨论。

一、委托的实质

平常我们很容易应用委托——用C# delegate关键字定义委托,再用new操作符结构委托实例,然后通过调用委托实例来调用回调方法(就是用一个了委托对象的变量来取代方法名,这句话如果刚接触的人欠好懂得的话,这里给个例子:MyDelegate mydelegate =new Mydelegate(obj.mymethod),MyDelegate是定义的一个委托,假设定义的是没有参数的,然后调用委托实例是这样的——mydelegate(), 大家可以发现此时调用委托和调用方法的方法是如出一辙的,如果没有看前面mydelegate是个委托类型,大家都会以为这是直接调用一个方法,而不是调用委托实例,通过这个例子大家应当很容易明确了这句话了吧——用一个委托对象的变量来取代方法名),相信通过括号内的讲授后,相信大家又会对委托有进一步的懂得的——委托就是方法的取代品,委托变量此时着方法名,大家可以简略懂得委托是方法的一个 “外号”。

前面的都介绍了委托的一些应用和懂得的,现在就让我我们来进一步看看编译器和CLR在背后对我们用delegate 关键字定义的委托类型做了些什么事情的,前一个专题中我和大家说过委托是一个类,这么是有根据的,因为我们在IDE中定义一个委托类型时,最终是通过编译器将定义的代码转化为中间语言IL,然后再执行中间语言中的代码来转化为本机代码的,所以在Visual Studio中编写的代码只是一个包装而已,真真程序执行的是中间语言中的代码的。现在就看看编译器把我们定义的委托类型转化为什么样的中间语言代码的。

当我们在类中像上面这样定义一个委托时:

public delegate void DelegateTest(int parm);

编译器把我们定义的委托类型编译成一个上面这样的类:

Public class DelegateTest: System.MulticastDelegate
{
public DelegateTest(Object object, IntPtr method); public virtual Void Invoke(int32 parm); public virtual IAsyncResult BeginInvoke(Int32 parm, AsyncCallback callback, Object object ); public virtual void EndInvoke(IAsyncResult result); }

从中间语言的代码就可以很明显的看出我们在代码中写的委托,对于中间语言来说就是一个类,该类继承于FCL中定义的Systme.MulticastDelegate类型,所有委托类型都派生于MulticastDelegate,该类中还定义了四个方法,一个结构函数,Invoke方法,还有就是两个异步方法BeginInvoke和EndInvoke方法,关于这两个异步方法,大家可以查看我博客中的线程系列。大家可以用ILDasm.exe工具去查看委托生成的中间代码,上面我截的一个图(从我们定义的DelegateTest的前面的图标和我们主程序传递Program的图标是一样的,然而Program是一个类,很明显定义的委托DelegateTes也是一个类的):

由于所有委托类型都是继承于MulticastDelegate,MulticastDelegate又继承于Delegate,所以委托类型继承了MulticastDelegate的字段、属性和方法,在这些成员中,有三个非公共字段与后面专题要介绍的委托链有关,所以在这里先列出来的:

    每日一道理
喜马拉雅直冲霄汉,可上面有攀爬者的旗帜;撒哈拉沙漠一望无垠,可里面有跋涉者的脚印;阿尔卑斯山壁立千仞,可其中有探险者的身影;雅鲁藏布江湍急浩荡,可其中有勇敢者的故事。

字段

类型

解释

_target

System.Object

当委托对象包装的是一个静态方法时,这个字段为null,当委托对象包装一个实例方法时,这个字段引用的是方法地点的类的对象

_methodPtr

System.IntPtr

一个外部的整数,可以以为是方法句柄,标识着要调用的方法

_invocationList

System.Object

该字段平日为null,当结构一个委托链(多播委托)时,才引用一个委托数组。具体下一部分讲授。

大部分人可能会有这么个疑难,既然是非公共字段,所以在MSDN上是看不到的,那我是怎么晓得有这三个字段的呢?大家可以通过Reflector工具是反编译查看源码,Multicastdelegate 类通过MSDN查找可以晓得该类的命名空间和程序集,这样就可以更具程序集和命名空间用Reflector工具查看Multicastdelegate类的源码,上面是我用Reflector这个工具查看到的源码截图:

从截图中可以看出MulticastDelegate 类中只有两个字段,却没有前面表格中列出的_methodPtr和_target字段的,这两个字段是定义在Delegate类中,大家应用Reflector工具来查看的,这里就不具体贴图了,文章最后会给出Reflector工具下载链接的。

委托对象就是一个包装器,包装了一个方法和调用该方法时要操作的对象,例如,执行上面的代码时:

public  class Program
{
// 声明一个委托类型,它的实例引用一个方法
// 该方法归去一个int 参数,返回void类型
public delegate void DelegateTest(int parm); public static void Main(string[] args)
{
// 用静态方法来实例化委托
DelegateTest dtstatic = new DelegateTest(Program.method1); // 用实例方法来实例化委托
DelegateTest dtinstance = new DelegateTest(new Program().method2);
}
private static void method1(int parm)
{
Console.WriteLine("调用的是静态方法,参数值为:" + parm);
} private void method2(int parm)
{
Console.WriteLine("调用的是实例方法,参数值为:" + parm);
}
}

代码中dtstatic 和dtinstance变量引用了初始化好的DelegateTest委托对象,此时这两个委托对象的上面列出来的三个字段初始化情况如下图:

二、总结

本专题从中间语言的角度去详细剖析定义的委托类型经编译器转化后的的中间语言是怎样来解释一个委托类型的,得到的结论是——委托实际上是一个类,该类派生于MulticastDelegate类,且继承了该类的_target,_methodPtr和_invocationList这三个字段,当我们初始化一个委托对象时,此时就会先初始化这三个字段,对于包装实例方法和静态方法的委托,初始化这三个字段也有所不一样,在上面的截图中也所体现,这里引用了一个很重要的字段——_invocationList(即委托实例的调用列表),对于委托对象包装一个方法时,该字段为null,如果委托对象要包装多个方法时,此时_invocationList字段就会被初始化为引用一个委托对象的数组(就是指向委托对象的一个集合),具体这方面的内容将在下一专题介绍委托链中为大家详细介绍。 到这里,本专题的内容也结束了,希望通过本专题,大家可以更进一步的懂得C#中的委托。

Reflector工具的下载地址:http://files.cnblogs.com/zhili/Reflector.zip ,看完后认为有帮助的话,请大家多多赞下的,谢谢大家的支持。

文章结束给大家分享下程序员的一些笑话语录: 这个世界上只有10种人:懂得二进制的和不懂得二进制的。

---------------------------------
原创文章 By
方法和字段
---------------------------------

方法字段[C# 基础知识系列]专题二:委托的本质论的更多相关文章

  1. [C# 基础知识系列]专题二:委托的本质论 (转载)

    引言: 上一个专题已经和大家分享了我理解的——C#中为什么需要委托,专题中简单介绍了下委托是什么以及委托简单的应用的,在这个专题中将对委托做进一步的介绍的,本专题主要对委本质和委托链进行讨论. 一.委 ...

  2. [C# 基础知识系列]专题三:如何用委托包装多个方法——委托链 (转载)

    引言: 上一专题介绍了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的介绍都是委托只是封装一个方法,那委托能不能封装多个方法呢?因为生活中经常会听到, ...

  3. 链方法[C# 基础知识系列]专题三:如何用委托包装多个方法——委托链

    最近研究链方法,稍微总结一下,以后继续补充: 弁言: 上一专题分析了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的分析都是委托只是封装一个方法,那委 ...

  4. [C# 基础知识系列]专题一:深入解析委托——C#中为什么要引入委托

    转自http://www.cnblogs.com/zhili/archive/2012/10/22/Delegate.html 引言: 对于一些刚接触C# 不久的朋友可能会对C#中一些基本特性理解的不 ...

  5. [C# 基础知识系列]专题九: 深入理解泛型可变性

    引言: 在C# 2.0中泛型并不支持可变性的(可变性指的就是协变性和逆变性),我们知道在面向对象的继承中就具有可变性,当方法声明返回类型为Stream,我们可以在实现中返回一个FileStream的类 ...

  6. [C# 基础知识系列]专题四:事件揭秘

    转自http://www.cnblogs.com/zhili/archive/2012/10/27/Event.html 引言: 前面几个专题对委托进行了详细的介绍的,然后我们在编写代码过程中经常会听 ...

  7. [C# 基础知识系列]专题四:事件揭秘 (转载)

    引言: 前面几个专题对委托进行了详细的介绍的,然后我们在编写代码过程中经常会听到“事件”这个概念的,尤其是写UI的时候,当我们点击一个按钮后VS就会自动帮我们生成一些后台的代码,然后我们就只需要在Cl ...

  8. [C# 基础知识系列]专题八: 深入理解泛型(二)

    引言: 本专题主要是承接上一个专题要继续介绍泛型的其他内容,这里就不多说了,就直接进入本专题的内容的. 一.类型推断 在我们写泛型代码的时候经常有大量的"<"和"& ...

  9. [C# 基础知识系列]专题七: 泛型深入理解(一) (转载)

    引言: 在上一个专题中介绍了C#2.0 中引入泛型的原因以及有了泛型后所带来的好处,然而上一专题相当于是介绍了泛型的一些基本知识的,对于泛型的性能为什么会比非泛型的性能高却没有给出理由,所以在这个专题 ...

随机推荐

  1. 【Ajax】实现注册页面判断用户名是否可用的提示—异步加载

    效果如图 在注册或登录网站时,当我们输入错误格式的账号或信息时,会看到这种提示. 那怎么实现呢,通过ajax异步加载的方式,可以实现不刷新页面就显示出该提示. 实现 首先创建一个JSP,写一个简单的页 ...

  2. String.IsNullOrEmpty 方法

    参数 value:一个String引用 返回值 如果 value 参数为 空引用(在 Visual Basic 中为 Nothing) 或空字符串 (""),则为 true:否则为 ...

  3. longest common str

    #include <vector> #include <iostream> #include <string> using namespace std; int l ...

  4. acdream 1056 (黑白染色)

    题意:给你一些关系,每个关系是两只马的名字,表示这两个马不能在一个分组里,问你能否将这些马分成两组. 黑白染色,相邻的点染不同颜色.bfs搞即可,水题. /* * this code is made ...

  5. 【转】Ofbiz学习经验谈

    不可否认,OFBiz这个开源的系统功能是非常强大的,涉及到的东西太多了,其实对我们现在而言,最有用的只有这么几个:实体引擎.服务引擎.WebTools.用户权限管理.最先要提醒各位的是,在配置一个OF ...

  6. 带宽计算-大B与小b的区别

    原文来自:http://blog.sina.com.cn/s/blog_4b9c0e3601008yf9.html 在计算机网络.IDC机房中,其宽带速率的单位用bps(或b/s)表示:换算关系为:1 ...

  7. (转)我是如何在SQLServer中处理每天四亿三千万记录的

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...

  8. maven学习系列教程,第一课(web项目的搭建)

    1.现在一般eclipse都已经装好了maven板块,无需自行下载安装,所以我们的第一步就是新建一个maven project 2地址使用默认的就行 3这边筛选一下,选择webapp 4. 5.建好后 ...

  9. Core Java 学习笔记——2.基本数据类型&类型转换

    数据类型(8种基本类型:int/short/long/byte/float/double/char/boolean) 整型 int 4字节 -2 147 483 648~2 147 483 647 s ...

  10. 通过Unity3D发布IOS版游戏

    https://developer.apple.com/ 打开上面的苹果开发者网站,选择上面的"Member Center"登录进入.前提是,你注册了开发者账号,并且付了年费. 选 ...