1.IL基本资料
1.IL概述
IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermediate Language)的代码(来源百度)
2.查看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。
2.完整示例代码
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 ????}
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 结束
接下来我会一步一步分析代码,鉴于我也是初学,很多不懂的地方我也不敢乱说,只介绍我了解的,如果不对,谢谢指出。
3.简单分析IL代码
1.IL关键字说明
.class:说明这是一个class,这个很简单一看就懂
.method:说明这是一个方法,也很简单
private,public:访问修饰符,也不多说
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);
???// 方法 ???.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_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.逐句分析代码
1.
1 ?int i = 0;2 ?int j = i + 5;
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: 1B10 IL_0004: ldc.i4.5 //将数值【5】推送到计算堆栈上11 // 0x0261: 5812 IL_0005: add //相加,并将结果推送到计算堆栈上13 // 0x0262: 0B14 IL_0006: stloc.1 //弹出计算堆栈顶部的值并赋值到调用堆栈索引为1的位置(也就是把刚才相加的结果赋值到调用堆栈索引为1的位置)
2.
1 ?List<string> list = new List<string>()2 ?{3 ?????"1","2","3","4","5"4 };
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: 0010 IL_0017: nop //此位置到IL_0042都是重复此操作11 // 0x0274: 2512 IL_0018: dup13 // 0x0275: 72 05 00 00 7014 IL_0019: ldstr "2"15 // 0x027A: 6F 10 00 00 0A16 IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)17 // 0x027F: 0018 IL_0023: nop19 // 0x0280: 2520 IL_0024: dup21 // 0x0281: 72 09 00 00 7022 IL_0025: ldstr "3"23 // 0x0286: 6F 10 00 00 0A24 IL_002a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)25 // 0x028B: 0026 IL_002f: nop27 // 0x028C: 2528 IL_0030: dup29 // 0x028D: 72 0D 00 00 7030 IL_0031: ldstr "4"31 // 0x0292: 6F 10 00 00 0A32 IL_0036: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)33 // 0x0297: 0034 IL_003b: nop35 // 0x0298: 2536 IL_003c: dup37 // 0x0299: 72 11 00 00 7038 IL_003d: ldstr "5"39 // 0x029E: 6F 10 00 00 0A40 IL_0042: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)41 // 0x02A3: 0042 IL_0047: nop //无操作43 // 0x02A4: 0C44 IL_0048: stloc.2 //弹出顶部的值并放入调用堆栈索引为【2】的位置,此时深度为【0】
3.
1 IEnumerator<string> listt = list.GetEnumerator();2 while (listt.MoveNext())3 {4 ????Console.WriteLine(listt.Current);5 }
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: 0012 IL_0057: nop //无操作13 // 0x02B4: 0914 IL_0058: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】15 // 0x02B5: 6F 12 00 00 0A16 IL_0059: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() //调用get_Current(),将返回值推送到计算堆栈上,此时深度为【1】17 // 0x02BA: 28 13 00 00 0A18 IL_005e: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】19 // 0x02BF: 0020 IL_0063: nop //无操作21 // 0x02C0: 0022 IL_0064: nop //无操作23 24 // 0x02C1: 0925 IL_0065: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】26 // 0x02C2: 6F 14 00 00 0A27 IL_0066: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() //调用MoveNext(),返回的bool ?推送到计算堆栈上 ,此时深度为【1】28 // 0x02C7: 13 0429 IL_006b: stloc.s 4 // 弹出顶的值,放入调用堆栈索引为4的位置,此时深度为【0】30 // 0x02C9: 11 0431 IL_006d: ldloc.s 4 //加载调用堆栈中索引为4的值推送到计算堆栈,此时深度为【1】32 // 0x02CB: 2D E633 IL_006f: brtrue.s IL_0057 //如果为 true、非空或非零,则跳转到IL_0057的位置,此时深度为【0】34 // 循环结束
4.
1 foreach (var item in list)2 {3 ????Console.WriteLine(item);4 ?}5 6 Console.ReadLine();
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 .try10 {11 ????// 0x02D6: 2B 1312 ????IL_007a: br.s IL_008f //跳转到IL_008f13 ????// 循环开始 (head: IL_008f)14 ????// 0x02D8: 12 0515 ????IL_007c: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】16 ????// 0x02DA: 28 15 00 00 0A17 ????IL_007e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current() //调用get_Current() 获取当前迭代器当前位置的值 ,此时深度为【1】18 ????// 0x02DF: 13 0619 ????IL_0083: stloc.s 6 // 弹出顶的值,放入调用堆栈索引为6的位置,此时深度为【0】20 ????// 0x02E1: 0021 ????IL_0085: nop //无操作22 ????// 0x02E2: 11 0623 ????IL_0086: ldloc.s 6 //加载调用堆栈中索引为6的值推送到计算堆栈,此时深度为【1】24 ????// 0x02E4: 28 13 00 00 0A25 ????IL_0088: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】26 ????// 0x02E9: 0027 ????IL_008d: nop //无操作28 ????// 0x02EA: 0029 ????IL_008e: nop //无操作30 31 ????// 0x02EB: 12 0532 ????IL_008f: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】33 ????// 0x02ED: 28 16 00 00 0A34 ????IL_0091: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext() //调用MoveNext() 返回值为bool ,此时深度为【1】35 ????// 0x02F2: 2D E436 ????IL_0096: brtrue.s IL_007c //如果为 true、非空或非零,则跳转到IL_007c的位置,此时深度为【0】37 ????// 循环结束38 39 ????// 0x02F4: DE 0F40 ????IL_0098: leave.s IL_00a9 //退出受保护的代码区域,跳转到IL_00a941 } // .try 结束42 finally43 {44 ????// 0x02F6: 12 0545 ????IL_009a: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】 ,说明下:这个值是循环是的迭代器对象46 ????// 0x02F8: FE 16 02 00 00 1B47 ????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.aspx48 ????// 0x02FE: 6F 17 00 00 0A49 ????IL_00a2: callvirt instance void [mscorlib]System.IDisposable::Dispose() //调用Dispose(),释放迭代器,此时深度为【0】 50 ????// 0x0303: 0051 ????IL_00a7: nop //无操作52 ????// 0x0304: DC53 ????IL_00a8: endfinally //结束捕获54 } // 捕捉结束55 // 0x0305: 28 18 00 00 0A56 IL_00a9: call string [mscorlib]System.Console::ReadLine() //调用ReadLine(),此时深度为【1】 57 // 0x030A: 2658 IL_00ae: pop //移除当前位于计算堆栈顶部的值。 对于这个我是这样理解的:ReadLine() 会返回要给string类型的值,但是没有变量接收,所以会移除这个值59 // 0x030B: 2A60 IL_00af: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
4.结尾
以上都是本人的个人理解,如果不对,谢谢指出!
分享个我当时遇到过的题目:
List<string> _List = new List<string>();public string this[int i]{ ???get { return _List[i]; }}public string get_Item(int i){ ???return _List[i];}
问:这段代码有错么,如果有错在哪呢?
初识.Net IL
原文地址:http://www.cnblogs.com/FreeEasy/p/7744121.html