查看委托的IL

通过IL来查看委托的原理,

委托示例代码

写一个委托的类如下

using System;

 

namespace MyCollection

{

    //定义一个类,该类包含两个静态方法

    class IntOperations 

    {

        //求整数的倍数

        public void Twice(int num) 

        {

            Console.WriteLine("整数{0}的倍数是 {1}", num, num * 2);

        }

        //求整数的平方

        public static void Square(int num) 

        {

            Console.WriteLine("整数{0}的平方是 {1}\n", num, num * num);

        }

    }

 

    delegate void IntOp(int x); //定义一个委托

 

    public class DelegateExample

    {

        static void Main(string[] args)

        {

            //实例化一个IntOperations对象

            IntOperations mo = new IntOperations();

            //创建Twice方法的委托对象

            IntOp operations = new IntOp(mo.Twice);

            //创建并增加Square方法的委托对象

            operations += new IntOp(IntOperations.Square);

            

            operations(5);

            operations(8);

            //创建并移除Square方法的委托对象

            operations -= new IntOp(IntOperations.Square);

            operations(5);

            operations(8);

            Console.WriteLine("按任意键退出...");

            Console.ReadLine(); //让屏幕暂停,以方便观察结果

        }

    }

}

示例解释

上面代码比较简单:首先定义了一个包含两个方法的类IntOperations,然后定义了一个委托IntOp,最后用写了一个类MainProgram来演示结果。

示例运行结果

查看IL

通过IL查看这个类的Main方法

IL代码

.method private hidebysig static void  Main(string[] args) cil managed

{

  .entrypoint

  // Code size       118 (0x76)

  .maxstack  3

  .locals init ([0] class MyCollection.IntOperations mo,

           [1] class MyCollection.IntOp operations)

  IL_0000:  nop

  IL_0001:  newobj     instance void MyCollection.IntOperations::.ctor()

  IL_0006:  stloc.0

  IL_0007:  ldloc.0

  IL_0008:  ldftn      instance void MyCollection.IntOperations::Twice(int32)

  IL_000e:  newobj     instance void MyCollection.IntOp::.ctor(object,

                                                               native int)

  IL_0013:  stloc.1

  IL_0014:  ldloc.1

  IL_0015:  ldnull

  IL_0016:  ldftn      void MyCollection.IntOperations::Square(int32)

  IL_001c:  newobj     instance void MyCollection.IntOp::.ctor(object,

                                                               native int)

//将一个委托对象组合到一个委托链中

  IL_0021:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,

                                                                                          class [mscorlib]System.Delegate)

  IL_0026:  castclass  MyCollection.IntOp

  IL_002b:  stloc.1

  IL_002c:  ldloc.1

  IL_002d:  ldc.i4.5

//执行方法

  IL_002e:  callvirt   instance void MyCollection.IntOp::Invoke(int32)

  IL_0033:  nop

  IL_0034:  ldloc.1

  IL_0035:  ldc.i4.8

  IL_0036:  callvirt   instance void MyCollection.IntOp::Invoke(int32)

  IL_003b:  nop

  IL_003c:  ldloc.1

  IL_003d:  ldnull

  IL_003e:  ldftn      void MyCollection.IntOperations::Square(int32)

  IL_0044:  newobj     instance void MyCollection.IntOp::.ctor(object,

                                                               native int)

//从委托链上移除找到的委托对象

  IL_0049:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,

                                                                                         class [mscorlib]System.Delegate)

  IL_004e:  castclass  MyCollection.IntOp

  IL_0053:  stloc.1

  IL_0054:  ldloc.1

  IL_0055:  ldc.i4.5

  IL_0056:  callvirt   instance void MyCollection.IntOp::Invoke(int32)

  IL_005b:  nop

  IL_005c:  ldloc.1

  IL_005d:  ldc.i4.8

  IL_005e:  callvirt   instance void MyCollection.IntOp::Invoke(int32)

  IL_0063:  nop

  IL_0064:  ldstr      bytearray (09 63 FB 4E 0F 61 2E 95 00 90 FA 51 2E 00 2E 00   // .c.N.a.....Q....

                                  2E 00 )                                           // ..

  IL_0069:  call       void [mscorlib]System.Console::WriteLine(string)

  IL_006e:  nop

  IL_006f:  call       string [mscorlib]System.Console::ReadLine()

  IL_0074:  pop

  IL_0075:  ret

} // end of method DelegateExample::Main

IL解析

源代码中的“operations+=new IntOp(IntOperations.Square);”对应于IL代码中的IL_0021行,就是调用System.Delegate类的 Combine方法,它将一个委托对象组合到一个委托链中去(关于委托链请参见:参考文献1的P377页),委托链上增加了方法Square。不过只有相 同类型的委托才可以组合。

同理,“operations-=new IntOp(IntOperations.Square);”对应于代码IL_0049行,调用System.Delegate类的Remove方法从委 托链上移除找到的委托对象。

当然,如果把委托链上所有的方法都移出去,那么委托就没有可以调用的方法。这个时候如果你在引用这个委托的话那么肯定不能通过编译,因为编译器没有方法可以处理对象。

如果从类的角度考虑委托,那么就会容易理解一些。当然,如果你不用ILdasm反汇编一下,就看不到背后的秘密了。

所以,蔡学镛说:.Net程序员可以不会用IL Assembly写程序,但是至少要看得懂反汇编出来的IL Assembly Code。

文献资料

推荐一篇好文章:通过IL来认识和使用委托

IL查看委托的更多相关文章

  1. IL查看泛型

    查看泛型的IL 我们在开发中经常用到泛型,下面一起通过IL来查看泛型背后做了那些工作 示例代码 示例代码如下: using System;   namespace MyCollection { pub ...

  2. IL查看override

    查看override的IL Override示例 下面我们看一个Override的Example namespace MyCollection { public class MyBase { publ ...

  3. 30分钟?不需要,轻松读懂IL

    先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点这些虚头巴脑的东西.最重要的理由就是一个 ...

  4. CLR via C#(12)-委托Delegate

    本来按照进度应该学习事件了,可总觉得应该委托在前,事件在后,才好理解. 委托是一个类,它提供了回调函数机制,而且是类型安全的.使用委托可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数 ...

  5. 方法字段[C# 基础知识系列]专题二:委托的本质论

    首先声明,我是一个菜鸟.一下文章中出现技术误导情况盖不负责 引言: 上一个专题已和大家分享了我懂得的——C#中为什么须要委托,专题中简略介绍了下委托是什么以及委托简略的应用的,在这个专题中将对委托做进 ...

  6. 读懂IL

    读懂IL 先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点这些虚头巴脑的东西.最重要的理 ...

  7. .NEL IL实现对象深拷贝

    对于深拷贝,通常的方法是将对象进行序列化,然后再反序化成为另一个对象.例如在stackoverflow上有这样的解决办法:https://stackoverflow.com/questions/785 ...

  8. 【转】.NET IL实现对象深拷贝

    对于深拷贝,通常的方法是将对象进行序列化,然后再反序化成为另一个对象.例如在stackoverflow上有这样的解决办法:https://stackoverflow.com/questions/785 ...

  9. .NET IL实现对象深拷贝

    对于深拷贝,通常的方法是将对象进行序列化,然后再反序化成为另一个对象.例如在stackoverflow上有这样的解决办法:https://stackoverflow.com/questions/785 ...

随机推荐

  1. 对getElementsByTagName("*")获取全部元素的总结

    var all=document.getElementsByTagName("*")      //获取整个页面的标签元素 alert(all.length);           ...

  2. 为什么要选择Sublime Text3?

    为什么要选择Sublime Text3? Sublime Text3 自动保存,打开图片 跨平台启动快!!!!多行游标,太好用. 插件,简直选不过来. 代码片段 VIM兼容模式 菜单栏基础功能介绍 F ...

  3. Atitit.木马病毒的免杀原理---sikuli 的使用

    Atitit.木马病毒的免杀原理---sikuli 的使用 1. 使用sikuli java api1 1.1. 3. Write code!1 2. 常用api2 2.1. wait 等待某个界面出 ...

  4. MSCRM 迁移 数据库 服务器

    Move the Microsoft Dynamics CRM databases to another SQL Server and SQL Server Reporting Services se ...

  5. C#获取本地系统日期格式

    我们可以通过使用DataTime这个类来获取当前的时间.通过调用类中的各种方法我们可以获取不同的时间:如:日期(2008-09-04).时间(12:12:12).日期+时间(2008-09-04 12 ...

  6. WEB程序调用客户端程序

    最近一个项目中要点击WEB页面上的链接启动自己编写的程序,而且还要接收参数,google了1.5小时,终于初步试验通过了. 尝试google了:web send message windows for ...

  7. 据说是百度ios面试题

    百度面试题:   一面:知识点 Objective C runtime library: Objective C的对象模型,Block的底层实现结构,消息发送,消息转发,内存管理 CoreData : ...

  8. Android群英传笔记系列三 view的自定义:实现一个模拟下载

    1.实现效果:动态显示进度(分别显示了整个的动态改变的过程,然后完成后,弹出一个对话框)       2.实现过程:可以分为绘制一个圆,圆弧和文本三部分,然后在MainAcitivity中通过线程模拟 ...

  9. MyBatis入门(一)---基本使用

    一.MyBatis简介 1.1.概述 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. M ...

  10. JAVA基础学习day14--集合一

    一.集合的出现 1.1.集合简述 面向对象语言对事物的体现都是以对象形式,为了方便对多个对象的操作,就对象对象进行存储,集合就是存仪储对象最常用的一种试 1.2.数组和集合都是容器 数组也存对象,存储 ...