從如下幾個方面總結一下C#的值類型與引用類型:編程
- 定義
- 值類型與引用類型的區別
- 值類型與引用類型的選擇
- 拆裝箱
- 如何避免拆裝箱
.Net框架最主要的兩個組成部分是CLR和框架類庫(FCL),而CLR最主要的兩個組成部分部分是CTS(公共類型系統)和CLS(公共語言規範)。簡單來講,CTS就是一種規範,它容許遵照此規範的編程語言能夠存在什麼類型,每種類型是否能夠包含成員、以及能夠包含哪些成員。官方給出的CTS做用以下:數組
- 創建用於跨語言執行的框架。
- 提供面向對象的模型,支持在 .NET 實現上實現各類語言。
- 定義處理類型時全部語言都必須遵照的一組規則。
- 提供包含應用程序開發中使用的基本基元數據類型(如 Boolean、Byte、Char 等)的庫。
故,C#中的值類型與引用類型就遵循此規範。閉包
定義
- C# 中的數據類型能夠簡單的分爲值類型(結構、枚舉)和引用類型(類、接口、字符串、數組、委託、指針)。
- 值類型變量或常量的內容僅僅是一個值,例如整數int,小數float/double,布爾值等,換句話說就是,變量引用的位置就是值在內存中的位置。
- 引用類型比較複雜,它友兩部分組成:對象和對象引用。而引用類型的變量中的內容存儲的是對‘數據’存儲位置的引用,不是直接存儲‘數據’。
- 存儲開銷:
- 值類型所佔內存大小就是存儲字段所需內存。例如Book所需內存就是price、title、author內存的和。
- 引用類型要求爲引用和對象單獨分配存儲空間。對象除佔用了和字段同樣的字節數以外,還須要額外的管理空間開銷。
值類型實例的賦值老是會進行實例複製。 引用類型變量的賦值只會複製引用。 框架
查閱https://referencesource.microsoft.com,會發現 數值類型、布爾類型、字符類型 其實都屬於Strust類型編程語言
值類型與引用類型的區別
- 全部值類型都隱式派生自System.ValueType,它是System.Object的子類,該類確保值類型全部的的成員所有分配在棧上。(如下三個除外)
- 結構體若是含有引用類型成員,該成員會牽扯到堆的分配
- 靜態類型,若是一個變量時靜態的,那麼,不管她是什麼類型,都會分配到加載堆上
- 局部變量被捕獲升級爲密封類(閉包中涉及到)
因此,「值類型都分配在棧上,引用類型都分配在堆上」是不許確的
- 引用類型初始值爲null,值類型初始值爲0.
- 值類型不能被繼承,引用類型則能夠
- 值類型的聲明週期在其定義域內,離開定義域以後即被銷燬,而引用類型沒法肯定什麼時候被銷燬
裝箱與拆箱
裝箱與拆箱就是值類型與引用類型之間的轉換性能
裝箱過程
int i = 1;
object o = i;
複製代碼
- 在堆中申請內存,內存大小爲值類型大小,載加上額外的固定空間(類型對象指針和同步塊索引)
- 將值類型的字段值拷貝到新申請的內存中
- 返回新引用對象的內存地址
裝箱須要比原數據更多的空間, 由於它須要兩個引用類型的標準配置:類型對象指針和同步塊索引spa
拆箱過程
int b = (int) o;
複製代碼
- 檢查引用類型是否爲null,不然拋出NullReferenceException異常。檢查對象實例,確保它是給定值類型的一個裝箱值。不然拋出InvaildCastException異常。
- 將該值的實例複製到值類型變量中。
與拆箱比較,裝箱的性能消耗更大,由於引用對象的分配更復雜,成本也就更高,值類型分配在堆棧上,分配和釋放的效率都很高。指針