• ILSpy和ILDasm的使用


    一.工具介绍

    1. ILSpy.exe(点击下载):用来查看IL代码;

    2. ILDasm(点击下载):看.net Framework中的程序集中方法的源码(通过反编译),即BCL中的代码; 

    工具在开发工具中有,也可以从上面的连接链接中下载。

    二.C#程序的编译过程

    1. 预编译:从C#代码编译为MSIL中间语言代码的过程;

    2. 即时编译(JIT):从MSIL中间语言代码编译为机器代码的过程;

    三.简单的实践

    1. 从"+"号看预编译本质

    (1)C#源代码

    string result = "Hello" + "World!";
    Console.Write(result);

    (2)将工程Debug中EXE用ILDasm打开

    打开后如下图一:


    图一

    <1> 条目与原项目的对应关系

    说明:对应关系如下图二:

    图二

    (3)逐条讲解

    <1> 程序集清单(MANIFEST)

    说明:程序集清单,说明了项目的一些情况,里面有版本信息和共钥信息等等,只需做了解。如下图三:

    图三

    <2> 类(Class)的声明

    说明:如下图四,其中红色方框圈出的条目.class开头的为program类的声明。点击打开后可以看到,这个类是继承自System.Object。

    图四

    <3> 构造函数(默认构造函数)

    说明:如下图五可以看到一个构造函数。虽然我们在program里面并有写任何有关构造函数的代码,但是编译器在编译的时候,自动给我们加了一个默认的构造函数。从打开后的界面可以看到"call instace void [mscorlib]System.Object::ctor()",也就是说这个构造函数调用父类的构造函数。

    图五

    <4> Main函数

    说明:可以看到在右边的条目中,这个函数的左边方框里面有一个“s”的符号,这说明这个函数是静态的函数。打开后里面的内容如图六:

     

    图六

    (4)Main函数中的方法讲解

    <1> 查看IL指令

    说明一:在图六中红色方框内部,有很多IL的指令,我们可以通过上网查找来找到这些指令对应的含义。    

    点击进入指令查看网站

    说明二:下面列出图六中红色框内的指令含义。

     

    IL指令

    说明

    Ldstr

    推送对元数据中存储的字符串的新对象引用。

    Stloc.0

    从计算堆栈的顶部弹出当前值并将其存储到索引 处的局部变量列表中。

    Ldloc.0 

    将索引 处的局部变量加载到计算堆栈上。

    Call

    调用由传递的方法说明符指示的方法。

    Ret

    从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。

    <2> 程序IL代码分析

    说明:图六中红框内的代码的作用如下表格解释:

    代码

    解释

    Ldstr "HelloWorld!"

    将一个"HelloWorld!"字符串进行压栈

    Stloc.0  

    将栈顶的"HelloWorld!"字符串方法局部的0号变量中

    Ldloc.0 

    0号变量进行压栈,此时栈顶为0号变量,即为"HelloWorld!"字符串

    Call void [mscorlib]System.Console::Write(string)

    调用Console.Write函数,并且将栈顶的"HelloWorld!"字符串进行传入,执行完函数之后将栈顶的"HelloWorld!"字符串弹出栈(堆栈平衡,即进栈出栈数保持一致)

    (3)论一

    在预编译的时候”+“在程序中被认为是直接拼接。编译器将”"Hello" + "World!"”优化为了”"HelloWorld!"”,而不是在IL中进行拼接处理。

    (4)修改代码实验

    说明:我们对原来的代码进行修改。如下:

     

    string value1 = "Hello";
    string value2 = "World!";
    string ruselt = value1 + value2;
    Console.Write(ruselt);

     

     

    (5)重新编译后用ILDasm打开新生成的EXE

    说明:打开后找到Main函数。查看IL代码,如图七:


    图七

    (6)分析

    <1>代码功能

    说明:不难通过上面类似的分析得到如下表格功能。这个请读者尝试自己分析。

     

    代码块

    完成的功能

    第一个红框

    将两个字符串进行拼装,用的是string string.Concat(string,string)方法

    第二个红框

    将字符串显示了

    <2>问

    说明一:我们发现同样的“+”号在不同的用发下出现不同的编译后IL指令。

    说明二:我们还可以直到,这个代码等同于:

    string value1 = "Hello";
    string value2 = "World!";
    string ruselt = string.Concat(value1, value2);
    Console.Write(ruselt);

    (7)结论二

     

    <1> 两个字符串的相加,被预编译器优化成了字符串的拼接;

    <2> 两个字符串变量的相加,被预编译器编译成了对“string.Concat(string,string)”函数的调用;

    2. 用ILSpy查看刚才的string.Concat函数

    (1)打开ILDasm

    说明:打开如下图八如所示:

    图八

    (2) 找到string类中的Cocat(string,string)方法

    说明:如下图九如所示。可以看到传入的string如果为null,在方法内部会转换成string.Empty,所以不用担心如果传入Concat的参数为null的时候会报错的问题。


    图九

     

    四.不能算总结的总结

    (1) 用ILDasm查看了在不同情况下编译器对“+”的编译。通过对MSIL分析,我们初识了这个神奇的中间语言;

    (2) 用ILSpy看了string.Concat函数的源代码(反编译代码),这样就可以查看C#一些函数的内部写法。 

     

    五.写在最后

    (1) 项目的工程代码

    下载上面的工程代码(环境:vs2010)

    (2) 作者想说的话

    本文的目标读者是1年以上的C#开发人员。可能本文写的比较水,但在之后的章节中,难度会增加的很大。写这个文章的目标也是记录自己的学习过程,同时也是对大家的分享,如果有什么不足之处可以反馈给我。这样我也能写出更好的文章,也可以从交流中提高。之后会有IOC,AOP等等,或者是动态代码生成的实现的章节。也会有比较好玩的,例如C#语法糖等等在IL中的解释。希望自己和大家可以抱着一种虚心的态度一起提高,一起学习。最后,本文写于2018年5月6日星期日。

    (3) 下一篇

    预告:初探IL:从IL看C#语法(二)IL在表达式生成树中的运用技巧

     

    ******************转摘:https://blog.csdn.net/ZslLoveMiwa/article/details/80217969?utm_source=blogxgwz4

     
  • 相关阅读:
    洛谷P1012拼数(简单题排序技巧)
    欧拉函数(模板,相关问题持续更新中)
    欧几里得,扩展欧几里得(模板)
    快速幂(模板)
    读入读出挂
    webpack 使用style-loader,css-loader添加css样式
    webpack-dev-server工具
    webpack4 配置
    获取自定义属性值
    安装PS
  • 原文地址:https://www.cnblogs.com/linybo/p/13360430.html
Copyright © 2020-2023  润新知