知識儲備,如果您已經十分熟習這些,可以跳過
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