盡管實例構造函數只在new之後被調用 ,但靜態構造函數總是會首先被調用。IL會強制這個執行的順序。對基類構造函數的調用不是必須的。因 此,為了節省本書的篇幅,我們不會展示程序的所有代碼。
在某些情況中,如果我們不包括構造 函數的代碼,那麼程序就不會工作。只有在這些情況中,構造函數的代碼才會被包括進來。靜態構造函數 不會調用基類的構造函數,this也不會被傳遞到靜態函數中。
a.cs
class zzz
{
public static void Main()
{
int i = 6;
long j = 7;
}
}
a.il
.assembly mukhi {}
.class private auto ansi zzz extends System.Object
{
.method public hidebysig static void vijay() il managed
{
.entrypoint
.locals (int32 V_0,int64 V_1)
ldc.i4.6
stloc.0
ldc.i4.7
conv.i8
stloc.1
ret
}
}
在C#程序中,我們在Main函數中創建了2個變量i和j。它們是局部變量,是在棧上創建的 。請注意,在轉換到IL的過程中,變量的名稱會被丟棄。
在IL中,變量通過locals偽指令來創建 ,它會把自身的名稱分配給變量,以V_0和V_1等等作為開始。數據類型也會被修改——從int 修改為int32以及從long修改為int64。C#中的基本類型都是別名。它們都會被轉換為IL所能理解的數據類 型。
當前的任務是將變量i初始化為值6。這個值必須位於磁盤上或計算棧上。做這個事情的指令 是ldc.i4.value。i4就是從內存中獲取4個字節。
在上面語法中提到的value,是必須要放置到棧 上的常量。在值6被放置到棧上之後,我們現在需要將變量i初始化為這個值。變量i會被重命名為V_0,它 是locals指令中的第一個變量。
指令stloc.0獲取位於棧頂的值,也就是6,並將變量V_0初始化為 這個值。初始化一個變量的過程是相當復雜的。
第2個ldc指令將7這個值復制到棧上。在32位的機 器上,內存只能以32字節的塊(Chunk)來分配。同樣,在64位的機器上,內存是以64字節的塊來分配的 。
數值7被存儲為一個常量並只需要4個字節,但是long需要8個字節。因此,我們需要把4字節轉 換為8字節。指令conv.i8就是用於這個意圖的。它把一個8字節數字放在棧上。只有在這麼做之後,我們 才能使用stloc.1來初始化第2個變量V_1為值7。從而會有stloc.1指令。
因此,ldc系列用於放置 一個常量數字到棧上,而stloc用於從棧上獲取一個值,並將一個變量初始化為這個值。
a.cs
class zzz
{
static int i = 6;
public long j = 7;
public static void Main()
{
}
}
a.il
.assembly mukhi {}
.class private auto ansi zzz extends System.Object
{
.fIEld private static int32 i
.fIEld public int64 j
.method public hidebysig static void vijay() il managed
{
.entrypoint
ret
}
.method public hidebysig specialname rtspecialname static void .cctor() il managed
{
ldc.i4.6
stsfld int32 zzz::i
ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() il managed
{
ldarg.0
ldc.i4.7
conv.i8
stfld int64 zzz::j
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}