转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857771.html
续上文【翻译】MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API ,本文继续讲解类和异常处理。谨以这三篇译文纪念29年前的今日,那个让母亲今生难以忘记的幸福而又痛苦的日子。
类
在前面的程序中,我们在Main函数中调用类函数,在本程序中,我们将徐希如何定义类。本程序包含2个类: Class1和SampleClass,Class1带有函数Main,在Main中生成SampleClass的一个实例。
指令:
- .field—定义类成员。和关键字public、private、static等一起使用。
命令:
- stsfld static field—用堆栈中的值替换静态字段的值。
- ldfld field—把一个非静态字段装入堆栈。类实例的地址必须在调用本命令之前装入堆栈。
- ldarg.n—把第n个参数装入堆栈。在非静态函数中,第0个参数是一个隐含的参数,代表this。
- newobj constructor—用构造函数constructor生成一个类的实例。构造函数的参数必须在调用本函数之前先装入堆栈。一个类的实例会被生成并装入堆栈。
- callvirt instance function—调用一个对象的后期绑定方法。
代码:
.assembly Classes {} /* class SampleClass { private int m_n; private string m_s; public static int nStatic = 10; public SampleClass(int n, string s) { m_n = n; m_s = s; } public int Number { get { return m_n; } } public string String { get { return m_s; } } }; class Class1 { [STAThread] static void Main(string[] args) { SampleClass o = new SampleClass(1, "Sample"); Console.WriteLine(SampleClass.nStatic.ToString()); Console.WriteLine(o.Number.ToString()); Console.WriteLine(o.String); } } */ .class private auto ansi beforefieldinit SampleClass extends [mscorlib]System.Object { .field private int32 m_n // private int m_n; .field private string m_s // private string m_s; .field public static int32 nStatic // public static int nStatic; // 该私有静态构造函数由编译器生成 // (用以初始化类的静态成员) .method private hidebysig specialname rtspecialname static void .cctor() cil managed { .maxstack 8 // ************************************************* // nStatic = 10 // ************************************************* ldc.i4.s 10 // 把常量装入堆栈 // stsfld 命令把静态字段的值替换成堆栈中的值 stsfld int32 SampleClass::nStatic ret } // 构造函数 // public SampleClass(int n, string s) // .method public hidebysig specialname rtspecialname instance void .ctor(int32 n, string s) cil managed { .maxstack 8 // ************************************************* // 调用基类的构造函数 // ************************************************* ldarg.0 // 把第0个参数装入堆栈(隐含指针this) // 调用类Object的构造函数 call instance void [mscorlib]System.Object::.ctor() // ************************************************* // m_n = n // ************************************************* ldarg.0 // 把第0个参数装入堆栈(隐含指针this) ldarg.1 // 把第1个参数装入堆栈(n) // 把n的值存入this.m_n stfld int32 SampleClass::m_n // ************************************************* // m_s = s // ************************************************* ldarg.0 //把第0个参数装入堆栈(隐含指针this) ldarg.2 //把第2个参数装入堆栈(s) // 把s的值存入this.m_s stfld string SampleClass::m_s ret } // 数字型属性 .property instance int32 Number() { // 调用 get_Number .get instance int32 SampleClass::get_Number() } .method public hidebysig specialname instance int32 get_Number() cil managed { .maxstack 8 // 由编译器生成的变量 // 译注:实际上,只有Debug版的才有,Release版的就直接返回m_n .locals ([0] int32 tmp) // ************************************************* // 返回 m_n; // ************************************************* ldarg.0 // 装入第0个参数(this) ldfld int32 SampleClass::m_n // 装入由堆栈栈顶指针指向的对象的字段 stloc.0 // 存入第0个变量 ldloc.0 // 把第0个变量装入堆栈(函数的返回值) ret } // 字符型属性 .property instance string String() { .get instance string SampleClass::get_String() } .method public hidebysig specialname instance string get_String() cil managed { .maxstack 8 // 由编译器生成的变量 .locals ([0] string tmp) ldarg.0 // 装入第0个参数(this) ldfld string SampleClass::m_s // 装入由堆栈栈顶指针指向的对象的字段 stloc.0 // 存入第0个变量 ldloc.0 // 把第0个变量装入堆栈(函数的返回值) ret } } .class private auto ansi beforefieldinit Class1 extends [mscorlib]System.Object { // public的缺省构造函数 .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 // ************************************************* // 调用基类构造函数 // ************************************************* ldarg.0 // 装入thisr call instance void [mscorlib]System.Object::.ctor() // 类Objectr的构造函数 ret } // Main 函数 .method private hidebysig static void Main(string[] args) cil managed { // 本方法为程序的入口点 .entrypoint // 自定义属性 .custom instance void [mscorlib]System. STAThreadAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 .locals ([0] class SampleClass o, [1] int32 tmp) // 由编译器生成 // ************************************************* // o = new SampleClass(1, "Sample"); // ************************************************* ldc.i4.1 // 把常量1装入堆栈 ldstr "Sample" // 把字符常量装入堆栈 // 通过传入堆栈中的2个参数生成一个SampleClass的对象, // 并把他装入堆栈 newobj instance void SampleClass::.ctor(int32, string) stloc.0 // 存入第0个变量 // ************************************************* // 访问静态类成员 // Console.WriteLine(SampleClass.nStatic.ToString()); // ************************************************* //把静态字段的地址装入堆栈 ldsflda int32 SampleClass::nStatic // 为堆栈中的对象调用Int32::ToString call instance string [mscorlib]System.Int32 ::ToString() // 调用静态的WriteLine,其传入参数是堆栈中的字符串 call void [mscorlib]System.Console ::WriteLine(string) // ************************************************* // 调用实例函数 // Console.WriteLine(o.Number.ToString()); // ************************************************* ldloc.0 // 装入第0个变量 // 调用堆栈中对象的函数 call instance int32 SampleClass::get_Number() stloc.1 // 存入第1个变量 ldloca.s tmp // 把地址装入堆栈 call instance string [mscorlib]System.Int32 ::ToString() call void [mscorlib]System.Console ::WriteLine(string) // ************************************************* // 调用实例函数 // Console.WriteLine(o.String); // ************************************************* ldloc.0 callvirt instance string SampleClass::get_String() call void [mscorlib]System.Console ::WriteLine(string) // ************************************************* ldstr "Press Enter to continue" call void [mscorlib]System.Console ::WriteLine(class System.String) call int32 [mscorlib]System.Console::Read() pop // ************************************************* ret } }
异常处理
本程序使2个数相除,捕捉其除0异常。try/catch 块在MSIL中看起来像C#中的一样。
命令:
- leave.s label—离开try/catch等保护块。
代码:
.assembly Exception {} /* int x, y, z; string s; Console.WriteLine("Enter x:"); s = Console.ReadLine(); x = Int32.Parse(s); Console.WriteLine("Enter y:"); s = Console.ReadLine(); y = Int32.Parse(s); try { z = x / y; Console.WriteLine(z.ToString()); } catch (Exception e) { Console.WriteLine(e.Message); } */ .method static public void main() il managed { .entrypoint .maxstack 8 .locals ([0] int32 x, [1] int32 y, [2] int32 z, [3] string s, [4] class [mscorlib]System.Exception e) //输入 x, y ... .try { // ************************************************* // z = x / y; // ************************************************* ldloc.0 // 装入第0个变量 ldloc.1 // 装入第1个变量 div // 相除 stloc.2 // 把结果存入第2个变量 // ************************************************* // Console.WriteLine(z.ToString()); // ************************************************* ldloca.s z // 装入z的地址 call instance string [mscorlib]System.Int32 ::ToString() call void [mscorlib]System.Console ::WriteLine(string) leave.s END_TRY_CATCH // 退出try } catch [mscorlib]System.Exception { stloc.s e // 存入由堆栈抛出的异常 // ************************************************* // Console.WriteLine(e.Message); // ************************************************* ldloc.s e // load e callvirt instance string [mscorlib]System.Exception ::get_Message() call void [mscorlib]System.Console ::WriteLine(string) leave.s END_TRY_CATCH // 退出catch块 } END_TRY_CATCH: ret }