在C#中的關鍵字new,被轉換為匯編器指令newobj。 這就為IL不是一門低級匯編語言並且還可以在內存中創建對象提供了證據。指令newobj在內存中創建了一 個新的對象。即使在IL中,我們也不會知道new或newobj真正做了些什麼。這就證實了IL並不是另一門高 級語言,而是被設計為其它現代語言都能夠編譯為IL這樣一種方式。
使用newobj的規則和調用一 個函數的規則是相同的。函數名稱的完整原型是必需的。在這個例子中,我們調用了無參數的構造函數, 從而函數.ctor會被調用。在構造函數中,WriteLine函數會被調用。
正如我們先前承諾的,這裡 ,我們將要解釋指令ldarg.0。無論何時創建一個對象——一個類的實例,都會包括兩個基本 的實體:
函數
字段或變量,如data
當一個函數被調用時,它並不知道也不關心誰 調用了它或它在哪裡被調用。它從棧上檢索它的所有參數。沒有必要在內存中有一個函數的兩份復制。這 是因為,如果一個類包括了1兆的代碼,那麼每當我們對其進行new操作時,都會占據額外的1兆內存。
當new被首次調用時,會為代碼和變量分配內存。但是之後,在new上的每一次調用,只會為變量 分配新的內存。從而,如果我們有類的5個實例,那麼就只有代碼的一份復制,但是會有變量的5份獨立的 復制。
每個非靜態的或實例函數都傳遞了一個句柄,它表示調用這個函數的對象的變量位置。這 個句柄被稱為this指針。this由ldarg.0表示。這個句柄總是被傳遞為每個實例函數的第1個參數。由於它 總是被默認傳遞,所以在函數的參數列表中沒有提及。
所有的操作都發生在棧上。pop指令移出棧 頂的任何元素。在這個例子中,我們使用它來移除一個zzz的實例,它是通過newobj指令被放置在棧頂的 。
a.cs
class zzz
{
public static void Main()
{
System.Console.WriteLine("hi");
new zzz();
}
zzz()
{
System.Console.WriteLine("bye");
}
static zzz()
{
System.Console.WriteLine("byes");
}
}
a.il
.assembly mukhi {}
.class private auto ansi zzz extends System.Object
{
.method public hidebysig static void vijay() il managed
{
.entrypoint
ldstr "hi"
call void System.Console::WriteLine(class System.String)
newobj instance void zzz::.ctor()
pop
ret
}
.method private hidebysig specialname rtspecialname instance void .ctor() il managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ldstr "bye"
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
.method private hidebysig specialname rtspecialname static void .cctor() il managed
{
ldstr "byes"
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
}
Output
byes
hi
bye