天天看點

C#如何識别引用的真實類型(一)——轉載

知識儲備,如果您已經十分熟習這些,可以跳過

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

繼續閱讀