知識儲備,如果您已經十分熟習這些,可以跳過
1 什麼是引用?
引用是一個資料結構,包含了一個電腦記憶體堆地址的值,就類似C++中的指標一樣,本文中所有出現有關"引用"字句,讀者都可以把它理解成C,C++中的指標
再說一遍,引用 與 指標 是不同的,例如 GC在回收記憶體的時候,會修改引用的值,但本文的重點並不是講述 引用 與 指標的差別,所以,讀者可以把所有在這裡出現的 "引用" 理解成 c,c++ 中的指標
2 棧 與 堆, .net中的記憶體配置?
http://blog.csdn.net/cuike519/archive/2009/12/23/5063333.aspx ,如果你還不是很清楚這些,這裡有你所需要瞭解的
方法是類的,非靜態欄位是執行個體的
類中的方法(無論是靜態,還是非靜態)本質上都是屬於類的,類中非靜態欄位,是屬於類的執行個體的
正是因為這一點的不同,類中的方法代碼只建立了一份在記憶體中,而類中的非靜態欄位是隨著類的執行個體建立而建立的
理論上 ,執行個體一個類的對象,只需要在記憶體中分配 與 類中所有非靜態欄位總和大小 一致的記憶體就可以了
然後把分配的堆中記憶體位址的首地址 賦給 棧 中的引用
但,實際情況並非如此簡單,在.net 中,當執行個體化一個類的時候, 總共分配了( sizeof(void*) + 類中所有非靜態欄位大小總和 ) 的記憶體
那麼,那多出的 sizeof(void*) 是用來做什麼的呢?
P.S. 如果我沒有記錯的話 在32位的CPU下, sizeof(void*) 的大小是4個位元組
那多出來的4位元組,是做什麼的呢?
引用指向了一個記憶體位址,在該地址 + sizeof(void*) 後便緊跟著執行個體的非靜態欄位
每個類都擁有 sizeof(void*) 大小的"多餘"記憶體,那麼在那裡面,究竟有什麼呢?
在那裡面,總共有兩個東西
第一個是名為 syncblock 的索引
第二個是指向一個為公開的資料結構的控制代碼
不要小看那個未公開的資料結構,那裡有實際類型的相關資料,.net正是依靠它來準確識別引用的真實類型,就算你按照以下的例子做,CLR也會知道,誰到底是誰
Subclass sub = new Subclass();
BassClass B = (BassClass)sub;
B.GetType(); // CLR說,別裝B了,我知道你是 subclass 類的執行個體
真像已經大白,還想要知道更多?
1, 那個未公開的資料結構,有一個名字,叫做 CORINFO_CLASS_STRUCT(這個名字只是做參考,實際中,也許並不是這個名字),我們無法使用編程的方法直接存取這個資料結構,但是.net提供了一個類, System.RuntimeTypeHandle 允許我們用已經定義好的方法,訪問它
有關 System.RuntimeTypeHandle 的更多資訊,請參照MSDN
2, MSIL提供了兩個進行類型間相互轉換的IL指令
isinst
castclass
這兩個指令在編譯成機器碼的時候,都會產生訪問 CORINFO_CLASS_STRUCT以驗證是否可以進行轉換
它們唯一的不同是當驗證失敗時,castclass 拋出一個 System.InvalidCastException異常 (很熟習吧?)
isint 則會將一個為 null 的引用添加到棧頂 (MSIL是一門基於棧的語言,有興趣的童鞋,可以google下 :-))
在C#中
as ,is 操作符 被轉換成 isinst
() 強制類型轉換符 被轉換成 castclass