c#中Class和Struct使用與性能的區別


在Unity中很多已經定義為結構體的數據結構
  • Vector2, Vector3 和 Vector4
  • Rect
  • Color和Color32
  • Bounds
  • Touch
 

1.Class為引用類型,Struct為值類型

值類型與引用類型的區別這兩篇文章講得很好
 
雖然我們在.net中的框架類庫中,大多是引用類型,但是我們程序員用得最多的還是值類型。

  引用類型如:string,Object,class等總是在從托管堆上分配的,C#中new操作符返回對象的內存地址--也就是指向對象數據的內存地址。

 
  以下是值類型與引用類型的表:
  
    從這張圖可以看出,class(類)實例化出來的對象,指向了內存堆中分配的空間
                         struct(結構)實例化出來的對象,是在內存棧中分配
 
   所以,值類型和引用類型的區別就是:
            1、它們存儲的位置不一樣
            2、如果是引用類型,當兩個對象指向同一個地方,修改某一個的時候,其它對象的值會發生改變
當說到類的實例是傳引用時,實際過程是,先獲取一個指針,它指向對象在內存中的地址,然后傳遞這個指針。這很重要,因為一個類的實例,實際上可能很大,包含了很多域甚至其他對象。在這種情況下,賦值和傳遞整個實例可能非常影響性能,這就為什么要用傳地址來替代。
說到傳值時,實際過程是,對這個變量進行全克隆/拷貝,然后傳遞這個副本,原始值不變。結構體就是值類型,它是傳值的。這意味着,結構體是理想的小型數據結構。
 
由於引用類型在托管堆上分配,它只會在調用垃圾回收時才被清理。
值類型實在內存棧上分配,這就說明他們很容易被回收,而且不受垃圾回收的影響。
 
數據類型分隔為值類型和引用類型。值類型要么是堆棧分配的,要么是在結構中以內聯方式分配的。引用類型是堆分配的。引用類型和值類型都是從最終的基類 Object 派生出來的。當值類型需要充當對象時,就在堆上分配一個包裝(該包裝能使值類型看上去像引用對象一樣),並且將該值類型的值復制給它。該包裝被加上標記,以便系統知道它包含一個值類型。這個進程稱為裝箱,其反向進程稱為取消裝箱。裝箱和取消裝箱能夠使任何類型像對象一樣進行處理。
 

2.Class可以繼承父類,Struct不可以

所有結構體都默認繼承System.ValueType父類,所以不能繼承別的父類,ValueType是值類型的基類,詳見: https://msdn.microsoft.com/zh-cn/library/system.valuetype(VS.80).aspx
 
 
 

3.Struct必須在構造函數對所有變量賦值

結構體中所有變量都必須在構造函數中初始化
 

4.Struct沒有默認構造函數

 
Struct不允許有參數為空的構造函數
 

5.Struct與class的性能上的優缺點

關於值類型與引用類型的內存可以看這篇文章: https://msdn.microsoft.com/zh-cn/dd365372
 
值類型的實例化之后在內存的大小就是其所有內容物大小,也就是內容物內存越大、占用內存越大,存放在棧中,但是取值更快,不需要GC回收
引用類型把值存放在堆中,引用存在棧中,實例化時要在堆中取值,所以更消耗時間,但是更省內存,因為只用引用指針的大小,需要GC回收
 
 
  值類型 引用類型
內存
耗時
GC
     
     
 
 

6.Struct類型變量默認不可為空

也就是說,不能寫這個語句 struct != null,如果像這樣做的話,一定要加上?,為它取值要加上Value,判斷是否為空要用HasValue
Struct? struct = *****;
if(struct.HasValue)
     struct.Value.***** = ****;
值類型后面加問號表示可為空null(Nullable 結構)
Nullable是.NET 2.0中新提供的一種用於標明一個值類型是否可以為空的技術。
  對於一個類型,如果既可以給它分配一個值,也可以給它分配空引用null(表示沒有任何值),我們就說這個類型是可空的。
  因此,可空類型可表示一個值,或表示不存在任何值。例如,類似 String 的引用類型就是可空類型,而類似 Int32 的值類型不是可空類型。Nullable 結構支持將值類型擴展為可以為null,但不支持在引用類型上使用,因為引用類型本身就是可空的。
因為值類型的容量只夠表示適合於該類型的值,因此它不可為空;值類型沒有表示空值所需的額外容量。
例:public int? age;

等同 Nullable<int>

 

7.其他

值類型還有一個特性就是一旦修改值,就會產生一個值類型的副本
引用類型修改值,不會產生副本,但所有有該引用的值都會被修改

8.擴充

來自《深入理解C#》
值類型很能干,它們不需要垃圾回收,(除非被裝箱)不會因類型標識而產生開銷,也不需要解引用。
在其他方面,引用類型顯得更能干,在傳遞參數、賦值、將值返回和執行類似的操作時,只需復制4或8字節(要看運行的是是32位還是64位CLR),而不是賦值全部數據。
值類型傳給一個方法時,就得復制他的全部數據。
根據性能進行設計之前,需要衡量不同的選擇。
類型(不管是類還是結構體),擁有多少方法並不重要,每個實例所占用的內存不會受到影響。(代碼本身會消耗內存,但這只會發生一次,而不是每個實例都發生)
-update 2017/8/6



by wolf96 2017/7/19
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM