你的位置:首页 > ASP.net教程

[ASP.net教程]CLR基础(二)


假设现在你编写了一个Program.cs的代码文件,那么在Visual Studio命令提示工具中执行以下命令:
csc.exe /out:Program.exe /t:exe /r:mscorlib.dll Program.cs
这个命令行将指示C#编译器生成一个名为Program.exe的可执行文件(/out:Program.exe)。生成的文件属于Win32控制台应用程序类型(/t[target]:exe)。
一个托管的PE文件由4个部分构成:PE32(+)头、CLR头、元数据以及IL。使用ILDasm.exe(即IL Disassembler,IL反汇编器)可以检查一个托管PE文件中的元数据。下面讲一下关于ILDasm.exe的使用。
在"开始"菜单中找到"Visual Studio Tools",如图:

打开VS命令提示窗口,输入指令如:
ildasm D:\我的项目\程序测试\ILDasm使用测试\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
这时会打开ildasm.exe,如图:

 

注意在指令中要使用绝对路径,否则ildasm.exe会找不到你所要反汇编的exe或dll文件。也可只输入ildasm,此时只会打开不加载任何exe或dll的ildasm.exe窗口:

 

还可以通过为Visual Studio添加外部工具来更方便地使用ILDasm.exe工具,如图:

"命令"那一栏其实就是选择ILDasm.exe所在的目录,如笔者的:
C:\Program Files\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe
现在就用一个实际的例子进一步讲解有关ILDasm.exe的使用。新建控制台应用程序,代码很简单:

1 class Program2   {3     static void Main(string[] args)4     {5       Console.WriteLine("ILDasm使用测试");6       Console.ReadLine();7     }8 }

 保存生成后,打开ILDasm.exe,选择”文件”打开控制台应用程序生成的exe文件,如图:

 

随带附上ILDasm树状图的各种图标的说明:

鼠标双击树状图的子节点,便可看到相关的IL代码:

 

简单分析一下IL的代码及各种指令:
MANIFEST清单:MANIFEST是一个附加信息列表,主要包含程序集的一些属性,如程序集名称、版本号、哈希算法等;
ConsoleApplication1.Program类:

1 .class private auto ansi beforefieldinit ConsoleApplication1.Program2    extends [mscorlib]System.Object3 {4 } // end of class ConsoleApplication1.Program

 

 

1).class,表示Program是一个类。并且它继承自程序集—mscorlib的System.Object类;
2)private,表示访问权限;
3)auto,表示程序的内存加载全部由CLR来控制;
4)ansi,是为了在没有托管代码与托管代码之间实现无缝转换。这里主要指C、C++代码等;
5)beforefieldinit,是用来标记运行库(CLR)可以在静态字段方法生成后的任意时刻,来加载构造器(构造函数);

.otor方法(一个构造器,或者说constructor):

1 .method public hidebysig specialname rtspecialname 2     instance void .ctor() cil managed3 {4  // 代码大小    7 (0x7)5  .maxstack 86  IL_0000: ldarg.07  IL_0001: call    instance void [mscorlib]System.Object::.ctor()8  IL_0006: ret9 } // end of method Program::.ctor

 

1)cil managed:表示其中为IL代码,指示编译器编译为托管代码;
2).maxstack:表示调用构造函数.otor期间的评估堆栈(Evaluation Stack);
3)IL_0000:标记代码行开头;
4)ldarg.0:表示转载第一个成员参数,在实例方法中指的是当前实例的引用;
5)call:call一般用于调用静态方法,因为静态方法是在编译期就确定的。而这里的构造函数.otor()也是在编译期就制定的。而另一指令callvirt则表示调用实例方法, 它是在运行时确定的,因为如前述,当调用方法的继承关系时,就要比较基类与派生类的同名函数的实现方法(virtual和new),以确定调用的函数所属的Method Table;
6)ret:表示执行完毕,返回;

最后是Main()方法:

 1 .method private hidebysig static void Main(string[] args) cil managed 2 { 3  .entrypoint 4  // 代码大小    19 (0x13) 5  .maxstack 8 6  IL_0000: nop 7  IL_0001: ldstr   bytearray (49 00 4C 00 44 00 61 00 73 00 6D 00 7F 4F 28 75  // I.L.D.a.s.m..O(u 8                  4B 6D D5 8B )                   // Km.. 9  IL_0006: call    void [mscorlib]System.Console::WriteLine(string)10  IL_000b: nop11  IL_000c: call    string [mscorlib]System.Console::ReadLine()12  IL_0011: pop13  IL_0012: ret14 } // end of method Program::Main

 

1) .entrypoint指令表示CLR加载程序时,是首先从.entrypoint开始的,即从Main方法作为程序的入口函数;
2)ldstr:表示将字符串压栈,在这里就是将"Hello World." 压栈;
3)hidebysig:表示当把此类作为基类,存在派生类时,此方法不被继承,同上构造函数;
下面总结一下常用的IL指令:
1.newobj: 用于创建引用类型的对象;
2.ldstr:用于创建String对象变量;
3.newarr:用于创建数组型对象;
4.box:在值类型转换为引用类型的对象时,将值类型拷贝纸托管堆上分配内存;
现在对ILDasm的了解先告一段落,下面继续CLR之旅。上面讲到的控制台应用程序生成的exe文件其实就是一个程序集。CLR对程序集的解释是:程序集是一个或多个类型定义文件及资源文件的集合。为程序集添加资源文件,比如说常见的为一个Winform桌面程序添加一个自己的特色图标,可以在Visual Studio中选择项目”属性”,然后在”应用程序”选项卡中添加资源文件。

嵌入图标后,应用程序的可执行文件便会显示自己特有的图标。