查看委托的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. .NET Core创建一个控制台(Console)程序

    .NET Core版本:1.0.0-rc2 Visual Studio版本:Microsoft Visual Studio Community 2015 Update 2 开发及运行平台:Window ...

  2. API的非向后兼容性无论如何通常代表着一种比较差的设计

    不管一个类库或者工具方法实现多么的好,如果无法做到向后兼容性,通常会给用户带来很大的升级成本,很多对此的依赖如果希望在后续的升级和维护期间使用该类库的其他新增特性或者好处,将不得不推迟升级亦或是被迫接 ...

  3. 解决C#导出excel异常来自 HRESULT:0x800A03EC的方法 .

    解决C#导出excel异常来自 HRESULT:0x800A03EC的方法 .   xlBook.SaveAs(FilePath,Microsoft.Office.Interop.Excel.XlFi ...

  4. GridControl列自动匹配宽度

    //自动调整所有字段宽度this.gridView1.BestFitColumns(); //调整某列字段宽度this.gridView1.Columns[n].BestFit(); 大多是网上零散找 ...

  5. thinkPHP学习笔记(2)

    1.调试模式 设置调试模式部分代码如下: <?php define('APP_DEBUG',TRUE); // 开启调试模式 常量定义代码 require '/ThinkPHP框架所在目录/Th ...

  6. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q125-Q126)

    Question 125You are creating an application for SharePoint Server 2010.The application will run on a ...

  7. android 回调函数一:基本概念

    1.概念 客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数. 一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C ...

  8. 浅谈ClickableSpan , 实现TextView文本某一部分文字的点击响应

    超文本:http://www.baidu.com 这么一个效果:一行文本当中 前面显示黑色颜色的“超文本:”,后面显示红色颜色的“http://www.baidu.com” 并且要求红色字体的部分可以 ...

  9. 安装并运行hadoop

    本文地址:http://www.cnblogs.com/archimedes/p/run-hadoop.html,转载请注明源地址. 欢迎关注我的个人博客:www.wuyudong.com, 更多云计 ...

  10. Android中进程与线程

    常说的主线程(UI线程)是什么? 当一个Android程序刚启动的时候,我们的android系统就会启动一个带有一个单一线程的linux进程.默认情况下,所有的组件比如Activity都运行在同样的一 ...