1、結構(Struct)是CTS中五種基本類型之一,是一種值類型,一樣封裝了同屬一個邏輯單元的數據和行爲,這些數據和行爲經過結構中的成員表示;結構與類共享大多數相同的語法,但結構比類受到的限制更多,結構適用於表示輕量級類型;使用struct關鍵字定義結構:ide
//定義一個公共結構MyStruct public class MyStruct { public int MyField; //聲明一個int類型的公共實例字段 public void MyFunc() //聲明一個公共實例方法 { //do… } }
1.全部結構都直接隱式繼承自System.ValueType,不能再指定繼承自其它任何結構或類,即結構不支持繼承,但能夠實現一個或多個接口,同時結構也是隱式密封的,不能被繼承;函數
※將結構類型的對象強制轉換爲其所實現的任何接口類型或object類型時會致使裝箱操做,此時會將結構類型的對象包裝到託管堆內存上的引用類型對象內;this
2.因爲結構不支持繼承,所以結構不能被定義爲abstract或sealed;spa
3.結構不能被定義爲靜態的,但能夠聲明靜態成員;code
4.因爲結構不支持繼承,所以結構成員只能聲明爲public、internal或private的,不能聲明爲abstract、virtual和sealed;對象
※對於實例成員,不能在結構聲明中直接對其進行初始化;blog
※對於靜態成員,能夠在聲明時進行初始化,也能夠在靜態構造函數中對其初始化;繼承
※結構中不能聲明默認構造函數(無參數的構造函數),結構的默認構造函數由編譯器保留,並一直處於可用狀態,其做用是申請指定大小的內存空間,並將全部字節初始化爲0(即default(T));接口
※結構中能夠聲明帶參數的自定義構造函數,自定義構造函數的方法體中必須對全部的實例成員進行初始化,不然編譯器會報錯,私有實例成員只能在構造函數中進行初始化;內存
※結構不存在析構階段,不能聲明析構函數;
public struct MyStruct { public int MyNum; public string MyStr; public static int MyStaticNum = 1; public MyStruct(int myNum,string myStr) { MyNum = myNum; MyStr = myStr; } static MyStruct() { //對於靜態成員,能夠直接在聲明時初始化,也能夠在靜態構造函數中初始化 //MyStaticNum = 1; } }
2、能夠經過調用默認構造函數、自定義構造函數、使用對象初始化器或在聲明結構以後單獨初始化成員的方式構建結構實例;
1.使用運算符new或運算符default構建結構實例,並調用對應的構造函數:
MyStruct myStruct = new MyStruct(); //調用結構的默認構造函數,此時MyNum爲0,MyStr爲null myStruct = default(MyStruct); //與使用new MyStruct()徹底等效 myStruct = new MyStruct(1, "1"); //調用結構的自定義構造函數
2.與類不一樣,結構的實例化能夠不使用new運算符,此時不會調用任何構造函數,也不會初始化任何實例成員,內存分配效率提升,在訪問某個實例字段以前對該字段初始化便可:
MyStruct myStruct; //構建結構實例,但不調用構造函數 myStruct.MyNum = 1; int myNum = myStruct.MyNum; //訪問某個實例成員以前須要對其初始化
※一般適用於只使用結構中部分實例字段進行存儲和操做的狀況;
※只有當全部的實例字段都初始化完成後,才能調用其實例方法或將其用做參數、返回值;
※結構中存在私有實例字段時也可使用此種方式構建結構實例,但也意味着不能初始化完成其全部實例字段;
3、結構是值類型,變量和數據放在一塊兒,對結構類型的變量進行賦值、傳遞參數、方法返回等操做時都會產生新的變量,並會複製(即淺拷貝)原變量中的全部數據到新變量中,對新變量所作的任何修改都不會改變原變量的數據,只能將新變量從新賦值給原變量,在處理值類型的集合(如List<MyStruct>)時須要格外注意這點:
//當須要修改值類型集合中某個元素的數據時,須要先拿一個變量接收,修改完成後再賦值給集合 MyStruct myStruct = myStructList[0]; myStruct.MyNum = 20; myStructList[0] = myStruct;
1.結構類型可用做可空類型,此時依然是值類型,可空類型的變量可賦值爲null;
MyStruct? myStruct = null;
4、自定義結構的最佳實踐:
public struct MyStruct : IEquatable<MyStruct> //實現IEquatable<T>接口用於泛型 { public int MyNum; public override bool Equals(object obj) //會對實參進行裝箱 { if (!(obj is MyStruct)) { return false; } MyStruct other = (MyStruct)obj; //拆箱 return this.Equals(other); } public override int GetHashCode() //避免使用散列集合類時裝箱並提供高效實現 { return MyNum.GetHashCode(); } public override string ToString() //避免裝箱 { return MyNum.ToString(); } public bool Equals(MyStruct other) //避免比較時實參裝箱,避免使用泛型時裝箱 { return this.MyNum == other.MyNum; } public static bool operator ==(MyStruct left, MyStruct right) //比較時一般採用==運算符 { return left.Equals(right); } public static bool operator !=(MyStruct left, MyStruct right) { return !(left == right); } }
※若是須要進行大小比較,還應該實現接口IComparable<T>並重載運算符<=和>=;
若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕,您的承認是我寫做的最大動力!
做者:Minotauros
出處:https://www.cnblogs.com/minotauros/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。