续上文【翻译】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
}
Downloads