標籤:too ttext 層級 line birt 執行 www 派生 log
C# 結構體 struct
C#中結構類型和類類型在文法上非常相似,他們都是一種資料結構,都可以包括資料成員和方法成員。
結構和類的區別:
1、結構是實值型別,它在棧中分配空間;而類是參考型別,它在堆中分配空間,棧中儲存的只是引用。
2、結構類型直接儲存成員資料,讓其他類的資料位元於對中,位於棧中的變數儲存的是指向堆中資料對象的引用。
C#中的簡單類型,如int、double、bool等都是結構類型。如果需要的話,甚至可以使用結構類型結合運算子運算重載,再為C#語言建立出一種新的實值型別來。
由於結構是實值型別,並且直接儲存資料,因此在一個對象的主要成員為資料且資料量不大的情況下,使用結構會帶來更好的效能。
一、聲明結構的文法 - struct關鍵字
public struct AddressBook { //欄位、屬性、方法、事件 }
對於類而言,兩個變數指向同一個對象的情況是存在的,因此對這樣兩個變數中的任意一個進行操作,起結果必然會影響另外一個,因為它們指向的是同一個對象。
結構是實值型別,,直接包含它自己的資料,每個結構都儲存自己的一份資料,修改每一個結構的資料都不會對其他結構的資料造成影響。
二、給結構賦值
如果從結構中建立一個對象,並將該對象賦給某個變數,則該變數包含結構的全部值。複製類型為結構的變數時,將同時複製該結構所持有的所有資料。由於結構不是參考型別,因此結構類型的變數不能被賦予null值。
public class Program { static void Main(string[] args) { PersonStruct p1, p2; //與類一樣,但可以不new p1.Name = "張飛"; p1.MobilePhone = "13553663108"; p1.Birthday = DateTime.Now.AddYears(-10); p2 = p1; //將p1的值賦給p2 //由於是實值型別,因此賦值等於將全部值全部複製到p2的棧空間 p2.Name = "關羽"; //然後修改p2的值看是否會影響p1 Console.WriteLine(p1.Name); //輸出 張飛 沒影響 PersonClass p3 = new PersonClass(); p3.Name = "張飛"; p3.MobilePhone = "13553663108"; p3.Birthday = DateTime.Now.AddYears(-10); PersonClass p4 = new PersonClass(); p4 = p3; //將p3的值賦給p4 賦值後,由於是參考型別,因此兩個對象指向的是同一個地址(堆空間) p4.Name = "關羽"; //然後修改p4的值看是否會影響p3 Console.WriteLine(p3.Name); //輸出 關羽 有影響 Console.ReadKey(); } } public class PersonClass { public string Name; public string MobilePhone; public DateTime Birthday; } public struct PersonStruct { public string Name; public string MobilePhone; public DateTime Birthday; }
將一個結構變數賦值給另一個結構變數,就是把資料從一個結構複製到另一個結構。而類則不同,在類的變數之間,複製的是引用,而不是類資料。。因此當資料比較大的時候,這種資料複製機制會帶來較大的開銷。
三、建構函式
結構類型可以有執行個體建構函式和靜態建構函式,但不能有解構函式。
1、執行個體建構函式
結構類型都有一個預定義的,沒有參數的建構函式,這點與類是一樣的。此建構函式不允許刪除和重定義,並且這個無參數的建構函式會一直存在,並不會因為定義了其他帶參數的建構函式就消失,這一點和類不同。
注意如果沒有使用new運算子,是不可以使用資料成員的值(除非已顯示地設定了該資料成員的值)和調用函數成員的(除非所有資料成員均已經被賦值)。
四、靜態建構函式
和類一樣,結構類型也可以有靜態建構函式,靜態建構函式用於初始化待用資料成員。靜態建構函式有如下特點:
1、靜態建構函式不能有存取修飾詞和參數;
2、靜態建構函式不能訪問執行個體成員;
3、靜態建構函式無法直接進行調用;
結構和類的靜態建構函式的觸發規則不同,類的靜態建構函式是在建立第一個執行個體或引用任何靜態成員之前自動調用的,而結構的靜態建構函式在以下情況調用:
1、使用顯式聲明的建構函式進行初始化
2、調用結構的方法或訪問結構的靜態資料成員(無論是讀取還是賦值,訪問執行個體資料成員不會觸發CLR自動調用靜態建構函式)。
五、結構的多態和可繼承性
結構直接派生自System.ValueType,間接派生自System.Object,但結構是隱式密封的,不能作為基類在派生出其他的結構,也不能從類派生,但可以從介面派生。
結構的特性:
1、結構類型總是隱式密封的,因此在定義結構時不能使用sealed和abstract關鍵字;
2、因為結構不能作為基類,結構的成員不能使用如下存取修飾詞:protected和protected,internal;
3、結構的函數成員不能聲明為abstract和virtual,但是可以使用override關鍵字,用以覆寫它的基類System.ValueType中的方法。
六、結構的裝箱與拆箱
結構是實值型別,因此當它被轉換為object類型時,或者它所實現的介面類型的時候,就會執行裝箱操作;同樣,當執行相反操作的時候,就會執行拆箱操作。
七、結構和類的對比
結構 類
資料類型 實值型別 參考型別
是否必須使用new運算子執行個體化 否 是
是否可聲明無參數的建構函式 否 是
資料成員可否在聲明的同時初始化 聲明為const或static可以,資料成員不可以 可以
直接派生自什麼類型 System.ValueType 有
是否有解構函式 無 有
可否從類派生 否 可以
可否實現介面 可以 可以
執行個體化時在棧還是在堆分配記憶體 棧 堆,棧中儲存引用
該類型的變數可否被賦值為null 否 可以
可否定義私人的無參建構函式 否 可以
是否總有一個預設的無參建構函式 是 否
無論結構使用預定義的、無參數的建構函式,還是使用使用者定義的、有參數的建構函式進行初始化,都會初始化結構的資料成員。不過預定義的,無參的會將數值型初始化為預設值,參考型別初始化為null;而使用者自訂的初始化策略對個成員進行初始化。因此結構類型的資料成員不允許在聲明是顯式初始化。
八、效能
因為結構是實值型別,因此在為結構分配記憶體,或者當結構超出了範圍被刪除時,效能會非常好,因為他們將內聯或者儲存在堆棧中。當把一個結構類型的變數賦值給另一個結構時,對效能的影響取決於結構的大小,如果結構的資料成員非常多而且複雜,就會造成損失,接下來使用一段代碼來說明這個問題。
結構和類的適用場合分析:
1、當堆棧的空間很有限,且有大量的邏輯對象時,建立類要比建立結構好一些;
2、對於點、矩形和顏色這樣的輕量對象,假如要聲明一個含有許多個顏色對象的數組,則CLR需要為每個對象分配記憶體,在這種情況下,使用結構的成本較低;
3、在表現抽象和多層級的對象層次時,類是最好的選擇,因為結構不支援繼承。
4、大多數情況下,目標類型只是含有一些資料,或者以資料為主。
C# 結構體 struct