首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

CLR 筆記:基元、引用與值類型——裝箱拆箱、相等性與哈希碼

     編輯:關於.NET

5.1 基元類型

  • 編譯器直接支援的資料類型稱為基元類型,直接對應 FCL 型別(如 using string = System.String; 自動產生)。
  • FCL 型別在 C# 有對應基元類型,但 CLS 未必有(如 SByte, UInt16)。
  • C# 允許「安全」時隱式轉型(無資料遺失),Int32→Int64 隱式,反向需顯式(截斷處理)。
  • unchecked/checked 控制溢位檢查。每個運算子對應兩組 IL 指令(如 Add/Add.ovf)。預設關閉溢位檢查。
  • 控制方式:/checked+ 編譯器開關;checked/unchecked 運算子或區塊。Decimal 在 CLR 非基元類型,checked 對其無效。

5.2 引用類型與值類型

  • 引用類型從託管堆配置記憶體;值類型從執行緒堆疊配置。
  • 值類型無需指標,不受 GC 制約。
  • struct 和 enum 為值類型;其餘為引用類型(Int32, Boolean, Decimal, TimeSpan 皆為結構)。
  • struct → System.ValueType → System.Object;enum → System.Enum → System.ValueType。
  • 值類型皆為 sealed,可實作介面。
  • new 對值類型:C# 確保所有欄位初始化為 0;用 new 則視為已初始化。

使用值類型而非引用類型的情況

  1. 型別具有基元類型行為:不可變類型,欄位不變。
  2. 不需繼承任何類型。
  3. 型別為 sealed。
  4. 型別大小:實例較小 (<16KB) 或較大但不作為參數/回傳值使用。

5.3 值類型裝箱與拆箱

Boxing:1) 託管堆配置記憶體(含欄位、型別物件指標、同步區塊索引)。2) 複製欄位至新記憶體。3) 返回物件位址。→ 已裝箱物件生命週期超過未裝箱值類型(後者可重用,前者待 GC 回收)。

Unboxing:1) 取得已裝箱物件欄位位址。2) 將值從堆複製至堆疊值類型實例。→ 引用為 null 拋 NullReferenceException;無法正確轉型拋 InvalidCastException。

裝箱前型別為何,拆箱必須轉回該型別(基底/衍生類型皆不行):Int16 y = (Int16)(Int32)o;。拆箱返回已裝箱物件未裝箱部分的位址。

減少裝箱:多數方法多載為減少值類型裝箱(如 Console.WriteLine)。可為自己類別定義泛型方法(型別參數為值類型則無裝箱)。最壞情況手動控制:Object o = v; WriteLine("{0},{1},{2}", o, o, o); 僅裝箱一次。

未裝箱值類型無同步區塊索引,不可用 Monitor 或 lock。值類型可用 Object 虛方法 Equals, GetHashCode, ToString(ValueType 重寫,參數為未裝箱型別,CLR 以非虛方式直接呼叫)。非虛方法 GetType, MemberwiseClone 需裝箱。值類型實作介面並轉型為介面時需裝箱。

5.4 使用介面修改已裝箱值類型

範例展示:直接轉型修改為臨時物件;透過介面修改可改變原裝箱物件。

5.5 物件相等性與同一性

  • 相等性:Equality(型別與成員相同)。
  • 同一性:Identity(指向同一物件)。
  • Object.Equals 預設實作同一性。重寫 Equals 實現相等性:先檢查 null、再比較 GetType()、最後比較所有欄位。
  • 重寫 Equals 後無法測試同一性,Object.ReferenceEquals 提供同一性檢查。勿用 C# ==(可能重載),除非轉型為 Object。
  • ValueType 以反射重寫 Equals(檢測相等性),自訂值類型應重寫提升效能,勿呼叫 base.Equals()。

5.6 物件哈希碼

  • 重寫 Equals 必須重寫 GetHashCode,否則編譯器警告(Hashtable/Dictionary 要求相等物件哈希碼相同)。
  • 原理:新增/查找鍵值對皆透過 HashCode 定位。修改鍵值導致找不到,正確做法:先移除再新增。
  • 勿用 Object.GetHashCode 取得唯一性。FCL 提供 RuntimeHelpers.GetHashCode(靜態,非重寫)。ValueType 以反射實作 GetHashCode。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved