CLR via C# 第四&五章

CLR via C

第四章 類型基礎

  • 所有類型都是從System.Object派生
  • 類型轉換
  • 命名空間和程序集
  • 運行時的相互關係

4.1 所有類型都從System.Object派生

CLR要求所有類型都用System.Object派生。

換句話說,所有類型都能夠向上遞歸,顯式轉換爲System.Object類

在轉換過程中,如果涉及到值類型與引用類型的轉換的時候,也同樣會發生裝箱操作。

CLR要求所有對象都通過 new 操作符創建,這裏面存在一個new生效的過程

  1. 計算類型及所有基類型中所有實例字段需要的字節數。
  2. 分配1中計算的字節數,從而分配內存,將所有分配的字節都設爲0
  3. 初始化對象的類型對象指針和同步索引塊
  4. 調用類型的實例構造器(要一直往上走到System.Object

沒有與new操作符對應的delete操作符。因此無法 顯式 地釋放爲對象分配的內存(涉及到GC操作

4.2 類型轉換

CLR保證了類型安全。

CLR瞭解運行時的類型時什麼是通過由System.Object類中的非虛方法GetType得到的。

CLR允許對象轉換爲它的類型或者它的任何基類型。換句話說,子類型隱式轉換爲夫類型是CLR所允許的。而當父類型轉換成子類型的時候,因爲涉及到可能的內存分配問題,所以CLR中只允許進行顯式轉換。

is&as操作符

這兩個操作符,前者是進行類型檢查,返回的是Boolean值

後者進行的是賦值操作,返回的是指向該對象的指針or null

通過這兩個能夠快速的在類型安全的情況下進行類型檢查與類型檢查並將符合的類型進行賦值的操作。

4.3 命名空間與程序集

命名空間所進行的是 邏輯分組 在程序集層面,實際上命名空間所進行的應當是一個字符串替換的過程

因此我們必須要警惕儘量不要進行相同函數命名的過程。

在產生命名空間不同但是最後聲明瞭一樣的函數名的問題,實際上可以通過向前拓展對應的namespace來使得準確定位到某一個方法。

4.4 運行時的相互關係

當存在棧內函數的反覆調用的時候,對於上一個調用者來說,實際上會在當前的線程棧上預留一個返回的路標,通過這個地址,能夠在調用完B程序之後通過這個路標返回到A的線程棧中進行接下來的語句的執行。

第五章 基元類型、引用類型和值類型

  • 編程語言的基元類型
  • 引用類型和值類型
  • 對象哈希碼
  • dynamic基元類型

基元類型實際上就是一種能夠被編譯器直接理解的短類型,它算是一種define,但是最後的實現還是會落到System庫中的對應代碼去,如 stringString 實際上並沒有差別,實際上前者在編譯到IL代碼之後和後者是一樣的。

5.2 引用類型和值類型

兩者最大的區別在於 生存位置 前者生存於託管堆中,後者生存於線程棧中

其他的區別大致上有兩點1. 不會受GC影響 2. 不會像引用類型一樣實際上是通過指針來操作本身

引用類型的特點

  • 內存必須通過託管堆分配
  • 堆上分配的每個對象都有一些額外成員,這些成員必須初始化
  • 對象中的其他字節總設爲0
  • 從託管堆分配對象時,可能強制進行一次gc

    當聲明一個新的引用類型,然後將現有的引用類型賦值給它,這個時候並不會觸發一次新的引用類型的生成,因爲這樣子的名稱實際上可以認爲是一個存在與線程棧上面的指針,這個指針直接指向了託管堆中該引用類型的內存空間,也就是說,和之前生成的引用類型實際上沒有區別,只是多了一種喚醒它的名稱而已。對新的名稱修改同樣會造成本身類型的改變。

CLR可以根據使用者指定進行不同的內存排列。

5.3 值類型的裝箱和拆箱

當我們將值類型進行類型轉化的時候,一旦轉換爲了引用類型,這個時候就會顯式的發生裝箱的操作,裝箱結束之後這個值類型會存在一個在託管堆上面的副本,該副本就會變成一個引用類型。而當我們再次將這個副本轉換爲某個值類型的時候,則就會發生拆箱的操作。

因爲裝箱拆箱操作涉及到大量的內存申請和gc操作,所以實際上會造成非常大的時間浪費。

clipboard.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章