初识.Net IL

一.IL基本资料

1.IL概述

  IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermediate Language)的代码(来源百度)

2.查看IL的工具资料

  查看IL的工具和IL指令详细网上都有很多,我在这推荐几个我认为比较好用的。

1). ILdasm

  安装VS的时候会安装一款IL查看工具,【ildasm】,位于:C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools,依据版本不同可能实际路径不一样,但都位于:C:\Program Files (x86)\Microsoft SDKs\Windows目录下

2). ILSpy

  一款开源的C#反编译工具,个人比较喜欢用这个看,因为对于关键字有颜色标记,IL指令还能直接导航到微软网站查看此指令的解释,下载地址:点这里

3).Reflector

  当然还有老牌的Reflector,不过要注册。。。

4).IL指令详细

  这个网上有很多,MSDN上也有说明,我推荐一位博友的帖子 -->>> 点这里

3.IL运行空间

      

      Managed Heap(托管堆):这就是NET中的托管堆,用来存放引用类型,它是由GC(垃圾回收器自动进行回收)管理,每个进程共享此空间;

      Call Stack(调用堆栈):每个线程都有自己专属的调用堆栈, 保存运行期间所调用的方法,方法参数,返回地址,以及局部变量,当方法调用完毕后,会丢弃相关信息

      Evaluation Stack(计算堆栈):每个线程都有自己的线程栈,IL 里面的任何计算,都发生在 Evaluation Stack 上,其实就是一个 Stack 结构。可以 Push,也可以 Pop。

 二.完整示例代码

C#代码:

 1  static void Main(string[] args)
 2         {
 3             int i = 0;
 4             int j = i + 5;
 5             List<string> list = new List<string>()
 6             {
 7                 "1","2","3","4","5"
 8             };
 9             IEnumerator<string> listt = list.GetEnumerator();
10             while (listt.MoveNext())
11             {
12                 Console.WriteLine(listt.Current);
13             }
14 
15             foreach (var item in list)
16             {
17                 Console.WriteLine(item);
18             }
19 
20             Console.ReadLine();
21         }
22     }
C#代码

IL代码:

.class private auto ansi beforefieldinit SomeThingTest.Program
    extends [mscorlib]System.Object
{
    // 方法
    .method private hidebysig static 
        void Main (
            string[] args
        ) cil managed 
    {
        // 方法起始 RVA 地址 0x2050
        // 方法起始地址(相对于文件绝对值:0x0250)
        // 代码长度 176 (0xb0)
        .maxstack 3
        .entrypoint
        .locals init (
            [0] int32,
            [1] int32,
            [2] class [mscorlib]System.Collections.Generic.List`1<string>,
            [3] class [mscorlib]System.Collections.Generic.IEnumerator`1<string>,
            [4] bool,
            [5] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>,
            [6] string
        )

        // 0x025C: 00
        IL_0000: nop
        // 0x025D: 16
        IL_0001: ldc.i4.0
        // 0x025E: 0A
        IL_0002: stloc.0
        // 0x025F: 06
        IL_0003: ldloc.0
        // 0x0260: 1B
        IL_0004: ldc.i4.5
        // 0x0261: 58
        IL_0005: add
        // 0x0262: 0B
        IL_0006: stloc.1
        // 0x0263: 73 0F 00 00 0A
        IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
        // 0x0268: 25
        IL_000c: dup
        // 0x0269: 72 01 00 00 70
        IL_000d: ldstr "1"
        // 0x026E: 6F 10 00 00 0A
        IL_0012: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
        // 0x0273: 00
        IL_0017: nop
        // 0x0274: 25
        IL_0018: dup
        // 0x0275: 72 05 00 00 70
        IL_0019: ldstr "2"
        // 0x027A: 6F 10 00 00 0A
        IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
        // 0x027F: 00
        IL_0023: nop
        // 0x0280: 25
        IL_0024: dup
        // 0x0281: 72 09 00 00 70
        IL_0025: ldstr "3"
        // 0x0286: 6F 10 00 00 0A
        IL_002a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
        // 0x028B: 00
        IL_002f: nop
        // 0x028C: 25
        IL_0030: dup
        // 0x028D: 72 0D 00 00 70
        IL_0031: ldstr "4"
        // 0x0292: 6F 10 00 00 0A
        IL_0036: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
        // 0x0297: 00
        IL_003b: nop
        // 0x0298: 25
        IL_003c: dup
        // 0x0299: 72 11 00 00 70
        IL_003d: ldstr "5"
        // 0x029E: 6F 10 00 00 0A
        IL_0042: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
        // 0x02A3: 00
        IL_0047: nop
        // 0x02A4: 0C
        IL_0048: stloc.2
        // 0x02A5: 08
        IL_0049: ldloc.2
        // 0x02A6: 6F 11 00 00 0A
        IL_004a: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
        // 0x02AB: 8C 02 00 00 1B
        IL_004f: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
        // 0x02B0: 0D
        IL_0054: stloc.3
        // 0x02B1: 2B 0E
        IL_0055: br.s IL_0065
        // 循环开始 (head: IL_0065)
            // 0x02B3: 00
            IL_0057: nop
            // 0x02B4: 09
            IL_0058: ldloc.3
            // 0x02B5: 6F 12 00 00 0A
            IL_0059: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
            // 0x02BA: 28 13 00 00 0A
            IL_005e: call void [mscorlib]System.Console::WriteLine(string)
            // 0x02BF: 00
            IL_0063: nop
            // 0x02C0: 00
            IL_0064: nop

            // 0x02C1: 09
            IL_0065: ldloc.3
            // 0x02C2: 6F 14 00 00 0A
            IL_0066: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
            // 0x02C7: 13 04
            IL_006b: stloc.s 4
            // 0x02C9: 11 04
            IL_006d: ldloc.s 4
            // 0x02CB: 2D E6
            IL_006f: brtrue.s IL_0057
        // 循环结束

        // 0x02CD: 00
        IL_0071: nop
        // 0x02CE: 08
        IL_0072: ldloc.2
        // 0x02CF: 6F 11 00 00 0A
        IL_0073: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
        // 0x02D4: 13 05
        IL_0078: stloc.s 5
        .try
        {
            // 0x02D6: 2B 13
            IL_007a: br.s IL_008f
            // 循环开始 (head: IL_008f)
                // 0x02D8: 12 05
                IL_007c: ldloca.s 5
                // 0x02DA: 28 15 00 00 0A
                IL_007e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
                // 0x02DF: 13 06
                IL_0083: stloc.s 6
                // 0x02E1: 00
                IL_0085: nop
                // 0x02E2: 11 06
                IL_0086: ldloc.s 6
                // 0x02E4: 28 13 00 00 0A
                IL_0088: call void [mscorlib]System.Console::WriteLine(string)
                // 0x02E9: 00
                IL_008d: nop
                // 0x02EA: 00
                IL_008e: nop

                // 0x02EB: 12 05
                IL_008f: ldloca.s 5
                // 0x02ED: 28 16 00 00 0A
                IL_0091: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
                // 0x02F2: 2D E4
                IL_0096: brtrue.s IL_007c
            // 循环结束

            // 0x02F4: DE 0F
            IL_0098: leave.s IL_00a9
        } // .try 结束
        finally
        {
            // 0x02F6: 12 05
            IL_009a: ldloca.s 5
            // 0x02F8: FE 16 02 00 00 1B
            IL_009c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
            // 0x02FE: 6F 17 00 00 0A
            IL_00a2: callvirt instance void [mscorlib]System.IDisposable::Dispose()
            // 0x0303: 00
            IL_00a7: nop
            // 0x0304: DC
            IL_00a8: endfinally
        } // 捕捉结束

        // 0x0305: 28 18 00 00 0A
        IL_00a9: call string [mscorlib]System.Console::ReadLine()
        // 0x030A: 26
        IL_00ae: pop
        // 0x030B: 2A
        IL_00af: ret
    } // 方法 Program::Main 结束

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // 方法起始 RVA 地址 0x211c
        // 方法起始地址(相对于文件绝对值:0x031c)
        // 代码长度 8 (0x8)
        .maxstack 8

        // 0x031D: 02
        IL_0000: ldarg.0
        // 0x031E: 28 19 00 00 0A
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        // 0x0323: 00
        IL_0006: nop
        // 0x0324: 2A
        IL_0007: ret
    } // 方法 Program::.ctor 结束

} // 类 SomeThingTest.Program 结束
IL代码

  接下来我会一步一步分析代码,鉴于我也是初学,很多不懂的地方我也不敢乱说,只介绍我了解的,如果不对,谢谢指出。

三.简单分析IL代码

1.IL关键字说明

  

  .class:说明这是一个class,这个很简单一看就懂

  .method:说明这是一个方法,也很简单

  privatepublic:访问修饰符,也不多说

  hidebysig:相当于 new

  

  .entrypoint:表示程序的入口

  .locals init:本方法所使用的变量,只是对Call Stack的一个具体展现,这所使用的变量包含程序中正常声明的,以及运行中需要的 ,例: while (listt.MoveNext()),这个循环需要一个bool变量,在编译的时候这个变量是被声明在Call Stack中的,展现于.locals init

  

  .maxstack:对于这个我详细讲下,此表示本方法运行时,【同时】需要的最大的栈大小,也就是Evaluation Stack的最大深度。怎么理解这个最大深度

  举个栗子:

1 int a = 1;
2 int b = 2;
3 int c = 3;
4 int d = a + b + c;
5 Console.WriteLine(d);
C#代码
    // 方法
    .method public hidebysig 
        instance void test () cil managed 
    {
        // 方法起始 RVA 地址 0x2144
        // 方法起始地址(相对于文件绝对值:0x0344)
        // 代码长度 21 (0x15)
        .maxstack 2
        .locals init (
            [0] int32,
            [1] int32,
            [2] int32,
            [3] int32
        )

        // 0x0350: 00
        IL_0000: nop
        // 0x0351: 17
        IL_0001: ldc.i4.1
        // 0x0352: 0A
        IL_0002: stloc.0
        // 0x0353: 18
        IL_0003: ldc.i4.2
        // 0x0354: 0B
        IL_0004: stloc.1
        // 0x0355: 19
        IL_0005: ldc.i4.3
        // 0x0356: 0C
        IL_0006: stloc.2
        // 0x0357: 06
        IL_0007: ldloc.0
        // 0x0358: 07
        IL_0008: ldloc.1
        // 0x0359: 58
        IL_0009: add
        // 0x035A: 08
        IL_000a: ldloc.2
        // 0x035B: 58
        IL_000b: add
        // 0x035C: 0D
        IL_000c: stloc.3
        // 0x035D: 09
        IL_000d: ldloc.3
        // 0x035E: 28 1A 00 00 0A
        IL_000e: call void [mscorlib]System.Console::WriteLine(int32)
        // 0x0363: 00
        IL_0013: nop
        // 0x0364: 2A
        IL_0014: ret
    } // 方法 testtest::test 结束
IL代码

    IL_0000~IL_0006:此段为声明变量,并加载到Call Stack(调用堆栈)上,过程为:通过指令加载具体的【数值】到Evaluation Stack(计算堆栈),然后弹出并赋值到Call Stack(调用堆栈)

    IL_0007: ldloc.0:加载索引为0的局部到堆栈上,换种说法就是说:从Call Stack加载索引为0的变量到Evaluation Stack中,此时栈的深度为【1】

    IL_0008: ldloc.1:加载索引为1的局部到堆栈上,此时栈的深度为【2】

    IL_0009: add:将两个值相加并将结果推送到计算堆栈上。此步骤我个人是这样理解的:计算完成后会清空加载到栈上的两个值,此时栈的深度为【0】;并将计算出的值放入栈,此时栈的深度为【1】

    所以 a + b + c,是两两相加,直到计算完成,所以最大的栈深度为【2】

    对于.maxstack,有个方法比较特殊,那就是构造方法,【.maxstack 8】,这点其实我不是很明白,我看过很多都是8,不知是默认的,还是怎么的,如果知道的友友,还请留下你的见解

2.逐句分析代码

  C#对照编译的IL逐句分析,每句IL后面都有该指令详细说明

 1).片段1

1  int i = 0;
2  int j = i + 5;
C#代码
 1 // 0x025C: 00
 2 IL_0000: nop //无操作
 3 // 0x025D: 16
 4 IL_0001: ldc.i4.0 //将数值【0】推送到计算堆栈上
 5 // 0x025E: 0A
 6 IL_0002: stloc.0 //弹出计算堆栈顶部的值并赋值到调用堆栈索引为0的位置(也就是把刚才推送到的0赋值到调用堆栈索引为0的位置)
 7 // 0x025F: 06
 8 IL_0003: ldloc.0 //从调用堆栈上索引为0位置的值加载到计算堆栈上
 9 // 0x0260: 1B
10 IL_0004: ldc.i4.5 //将数值【5】推送到计算堆栈上
11 // 0x0261: 58
12 IL_0005: add //相加,并将结果推送到计算堆栈上
13 // 0x0262: 0B
14 IL_0006: stloc.1 //弹出计算堆栈顶部的值并赋值到调用堆栈索引为1的位置(也就是把刚才相加的结果赋值到调用堆栈索引为1的位置)
IL代码

2).片段2

1  List<string> list = new List<string>()
2  {
3      "1","2","3","4","5"
4 };
C#代码
 1 // 0x0263: 73 0F 00 00 0A
 2 IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor() //创建一个类型为List<string>的对象并推送到计算堆栈上,此时栈深度为【1】
 3 // 0x0268: 25
 4 IL_000c: dup //复制计算堆栈顶部的值,复制引用,并推送到计算堆栈上,此时深度为【2】
 5 // 0x0269: 72 01 00 00 70
 6 IL_000d: ldstr "1" //加载字符串【1】到计算堆栈上,此时深度为【3】
 7 // 0x026E: 6F 10 00 00 0A
 8 IL_0012: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) //调用Add方法,完成后清空刚才参与运算的变量,也就是List<string> 对象的副本,与字符串【1】,由于此方法没有返回值,并不会推送任何值到计算堆栈上,此时深度为【1】
 9 // 0x0273: 00
10 IL_0017: nop //此位置到IL_0042都是重复此操作
11 // 0x0274: 25
12 IL_0018: dup
13 // 0x0275: 72 05 00 00 70
14 IL_0019: ldstr "2"
15 // 0x027A: 6F 10 00 00 0A
16 IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
17 // 0x027F: 00
18 IL_0023: nop
19 // 0x0280: 25
20 IL_0024: dup
21 // 0x0281: 72 09 00 00 70
22 IL_0025: ldstr "3"
23 // 0x0286: 6F 10 00 00 0A
24 IL_002a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
25 // 0x028B: 00
26 IL_002f: nop
27 // 0x028C: 25
28 IL_0030: dup
29 // 0x028D: 72 0D 00 00 70
30 IL_0031: ldstr "4"
31 // 0x0292: 6F 10 00 00 0A
32 IL_0036: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
33 // 0x0297: 00
34 IL_003b: nop
35 // 0x0298: 25
36 IL_003c: dup
37 // 0x0299: 72 11 00 00 70
38 IL_003d: ldstr "5"
39 // 0x029E: 6F 10 00 00 0A
40 IL_0042: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
41 // 0x02A3: 00
42 IL_0047: nop //无操作
43 // 0x02A4: 0C
44 IL_0048: stloc.2 //弹出顶部的值并放入调用堆栈索引为【2】的位置,此时深度为【0】
IL代码

3).片段3

1 IEnumerator<string> listt = list.GetEnumerator();
2 while (listt.MoveNext())
3 {
4     Console.WriteLine(listt.Current);
5 }
C#代码
 1 IL_0049: ldloc.2 //加载调用堆栈索引为2的值到计算堆栈上,此时深度为【1】
 2 // 0x02A6: 6F 11 00 00 0A
 3 IL_004a: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator() //调用GetEnumerator(),并将返回值推送到计算堆栈上,注意【GetEnumerator(),返回的是Enumerator类型,此类型是个结构,是值类型,明白这一点才清楚下一步】,此时深度为【1】
 4 // 0x02AB: 8C 02 00 00 1B
 5 IL_004f: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> //进行装箱,转换成object类型,因为上一步返回的是值类型,所以在这一步进行装箱,过程:弹出上一步返回的值,进行装箱,并将对象的引用推送到计算堆栈上,此时深度为【1】      
 6 // 0x02B0: 0D
 7 IL_0054: stloc.3 //弹出顶部的值,并放入调用堆栈索引为3的位置 此时深度为【0】
 8 // 0x02B1: 2B 0E
 9 IL_0055: br.s IL_0065 // 直接跳转到 IL_0065处,开始循环
10 // 循环开始 (head: IL_0065)
11 // 0x02B3: 00
12 IL_0057: nop //无操作
13 // 0x02B4: 09
14 IL_0058: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】
15 // 0x02B5: 6F 12 00 00 0A
16 IL_0059: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() //调用get_Current(),将返回值推送到计算堆栈上,此时深度为【1】
17 // 0x02BA: 28 13 00 00 0A
18 IL_005e: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】
19 // 0x02BF: 00
20 IL_0063: nop //无操作
21 // 0x02C0: 00
22 IL_0064: nop //无操作
23 
24 // 0x02C1: 09
25 IL_0065: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】
26 // 0x02C2: 6F 14 00 00 0A
27 IL_0066: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() //调用MoveNext(),返回的bool  推送到计算堆栈上 ,此时深度为【1】
28 // 0x02C7: 13 04
29 IL_006b: stloc.s 4 // 弹出顶的值,放入调用堆栈索引为4的位置,此时深度为【0】
30 // 0x02C9: 11 04
31 IL_006d: ldloc.s 4 //加载调用堆栈中索引为4的值推送到计算堆栈,此时深度为【1】
32 // 0x02CB: 2D E6
33 IL_006f: brtrue.s IL_0057 //如果为 true、非空或非零,则跳转到IL_0057的位置,此时深度为【0】
34 // 循环结束
IL代码

4).片段4

1 foreach (var item in list)
2 {
3     Console.WriteLine(item);
4  }
5 
6 Console.ReadLine();
C#代码
 1 // 0x02CD: 00
 2 IL_0071: nop //无操作
 3 // 0x02CE: 08
 4 IL_0072: ldloc.2 //加载调用堆栈中索引为2的值推送到计算堆栈,此时深度为【1】
 5 // 0x02CF: 6F 11 00 00 0A
 6 IL_0073: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()//调用GetEnumerator() ,因为foreach的对象本身就是一个可迭代的对象,所以是使用迭代器,返回值同样是一个值类型,但是没有变量接收,所以不需要装箱,此时深度为【1】
 7 // 0x02D4: 13 05
 8 IL_0078: stloc.s 5 //弹出顶部的值,放入调用堆栈索引为5的位置,此时深度为【0】
 9 .try
10 {
11     // 0x02D6: 2B 13
12     IL_007a: br.s IL_008f //跳转到IL_008f
13     // 循环开始 (head: IL_008f)
14     // 0x02D8: 12 05
15     IL_007c: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】
16     // 0x02DA: 28 15 00 00 0A
17     IL_007e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current() //调用get_Current() 获取当前迭代器当前位置的值 ,此时深度为【1】
18     // 0x02DF: 13 06
19     IL_0083: stloc.s 6 // 弹出顶的值,放入调用堆栈索引为6的位置,此时深度为【0】
20     // 0x02E1: 00
21     IL_0085: nop //无操作
22     // 0x02E2: 11 06
23     IL_0086: ldloc.s 6 //加载调用堆栈中索引为6的值推送到计算堆栈,此时深度为【1】
24     // 0x02E4: 28 13 00 00 0A
25     IL_0088: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】
26     // 0x02E9: 00
27     IL_008d: nop //无操作
28     // 0x02EA: 00
29     IL_008e: nop //无操作
30 
31     // 0x02EB: 12 05
32     IL_008f: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】
33     // 0x02ED: 28 16 00 00 0A
34     IL_0091: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext() //调用MoveNext() 返回值为bool ,此时深度为【1】
35     // 0x02F2: 2D E4
36     IL_0096: brtrue.s IL_007c //如果为 true、非空或非零,则跳转到IL_007c的位置,此时深度为【0】
37     // 循环结束
38 
39     // 0x02F4: DE 0F
40     IL_0098: leave.s IL_00a9 //退出受保护的代码区域,跳转到IL_00a9
41 } // .try 结束
42 finally
43 {
44     // 0x02F6: 12 05
45     IL_009a: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】 ,说明下:这个值是循环是的迭代器对象
46     // 0x02F8: FE 16 02 00 00 1B
47     IL_009c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> //约束要对其进行虚方法调用的类型。 这里的话,清楚Call与Callvirt区别就知道为啥要这样了。。。我不是很了解这个,不敢乱说,望知道的友友留下你的见解,关于【constrained】指令的解释: https://msdn.microsoft.com/library/system.reflection.emit.opcodes.constrained.aspx
48     // 0x02FE: 6F 17 00 00 0A
49     IL_00a2: callvirt instance void [mscorlib]System.IDisposable::Dispose() //调用Dispose(),释放迭代器,此时深度为【0】 
50     // 0x0303: 00
51     IL_00a7: nop //无操作
52     // 0x0304: DC
53     IL_00a8: endfinally //结束捕获
54 } // 捕捉结束
55 // 0x0305: 28 18 00 00 0A
56 IL_00a9: call string [mscorlib]System.Console::ReadLine() //调用ReadLine(),此时深度为【1】 
57 // 0x030A: 26
58 IL_00ae: pop //移除当前位于计算堆栈顶部的值。 对于这个我是这样理解的:ReadLine() 会返回要给string类型的值,但是没有变量接收,所以会移除这个值
59 // 0x030B: 2A
60 IL_00af: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
IL代码

四.结尾

  以上都是本人的个人理解,如果不对,谢谢指出!

  分享个我当时遇到过的题目:

List<string> _List = new List<string>();
public string this[int i]
{
    get { return _List[i]; }
}

public string get_Item(int i)
{
    return _List[i];
}
C#代码

  问:这段代码有错么,如果有错在哪呢?

 

posted @ 2017-10-30 16:00  一直走总会到终点  阅读(1666)  评论(0编辑  收藏  举报