天天看點

《CLR via C#》精髓:引用類型和值類型一、引用類型和值類型的差別二、值類型的特點三、何時才需定義值類型

一、引用類型和值類型的差別

  1. 引用類型配置設定于托管堆上;值類型配置設定于線程棧上。由此可見,類型的執行個體最終配置設定在棧上還是堆上,由類型的定義者決定而不是由類型的使用者決定(這點與非托管的C/C++不同)。
  2. 引用類型執行個體存儲了對象資料在托管堆上的位址;值類型執行個體存儲了自身的資料。
  3. 引用類型受垃圾回收器控制;值類型不受垃圾回收器控制。
  4. 用class聲明的類型是引用類型;用struct聲明的類型是值類型。
  5. 引用類型總是處于已裝箱的形式;值類型對象有兩種可能的形式:未裝箱和已裝箱。
  6. 引用類型所繼承的Equals方法(由System.Object實作)比較兩個引用類型執行個體所持有的記憶體位址;值類型所繼承的Equals方法(由System.ValueType重寫)将比對兩個值類型執行個體的全部字段。GetHashCode方法亦是如此。
  7. 建立一個引用類型變量時,變量被初始化為null,表明引用類型的變量目前不指向任何有效對象;值類型的變量總是包含其基礎類型的一個值,并且,值類型的所有成員都初始化為0。
  8. 将一個引用類型變量賦給另一個引用類型變量時,隻複制記憶體位址;将一個值類型變量賦給另一個值類型變量時,會執行一次逐字段的複制。
  9. 兩個或多個引用類型變量可以引用堆中的同一個對象,是以,對一個變量執行操作可能影響到另一個變量引用的對象;值類型的變量是自成一體的對象,對一個值類型變量執行的操作不可能影響到其他值類型變量。
  10. 引用類型的執行個體在其記憶體被回收時将通過Finalize方法接收通知;值類型執行個體被回收時不會通過Finalize方法接收通知(事實上,C#不允許為值類型定義Finalize方法)。

二、值類型的特點

  1. 基本資料類型(Boolean、Char、Int32、Int64、Single、Double、Decimal等)都是值類型。
  2. 所有值類型都直接派生自System.ValueType類型,System.ValueType類型本身又直接派生自System.Object類型。
  3. 所有枚舉類型都直接派生自System.Enum類型,System.Enum類型本身又直接派生自System.ValueType類型,由此可知,枚舉類型都是值類型。
  4. 所有值類型都是隐式密封的(sealed),是以,值類型無法被作為基類使用,例如:你無法将Int32作為基類來定義任何新類型。
  5. 值類型中不存在虛方法,值類型的所有方法都不能是抽象的。
  6. 建立值類型時,無論是否使用了new操作符,C#都會保證類型中的所有字段都初始化為零。唯一的差別在于,如果使用了new操作符,C#會“認為”執行個體已經初始化了。
  7. 通路一個值類型時,不會出現NullReferenceException(著名的“未将對象引用設定到對象的執行個體”錯誤),因為值類型的變量不是指針。

三、何時才需定義值類型

  1. 類型具有基元類型的行為。即:是一個十分簡單的類型,沒有成員會修改類型的任何執行個體字段。
  2. 類型無需從其他任何類型繼承。
  3. 類型不會派生出其他任何類型。
  4. 類型的執行個體較小(16位元組以内),或者,類型的執行個體較大(超過16位元組),但不會作為方法的實參和傳回值。

轉載于:https://www.cnblogs.com/xuyanzheng/p/clr-via-csharp-reference-types-and-value-types.html