結構
什么是結構
結構是程序員定義的數據類型,與類非常相似。它們有數據成員和函數成員。結構與類的重要區別是:
- 類是引用類型而結構是值類型
- 結構是隱式密封的,這意味着它們不能被派生
聲明結構的語法與聲明類相似
關鍵字 ↓ struct SturctName { MemberDeclarations }
例:Point結構
struct Point { public int X; public int Y; } class Program { static void Main() { Point first,second,third; first.X=10;first.Y=10; second.X=20;second.Y=20; third.X=first.X+second.X; third.Y=first.Y+second.Y; Console.WriteLine("first: {0},{1}",first.X,first.Y); Console.WriteLine("second: {0},{1}",second.X,second.Y); Console.WriteLine("third: {0},{1}",third.X,third.Y); } }
結構是值類型
和所有值類型一樣,結構類型變量含有自己的數據。因此:
- 結構類型變量不能為null
- 兩個結構變量不能引用同一對象
例:結構變量的內存安排
class CSimple { public int X; public int Y; } struct Simple { public int X; public int Y; } class Program { static void Main() { var cs=new CSimple(); var ss=new Simple(); ... } }
對結構賦值
把一個結構賦值給另一個結構,就將一個結構的值復制給另一個結構。這和復制類變量不同,復制類變量時只復制引用。
例:結構變量賦值與類變量賦值的區別
class CSimple { public int X; public int Y; } struct Simple { public int X; public int Y; } class Program { static void Main() { CSimple cs1=new CSimple(),cs2=null; Simple ss1=new Simple(),ss2=new Simple(); cs1.X=ss1.X=5; cs1.Y=ss1.Y=10; cs2=cs1; ss2=ss1; } }
構造函數和析構函數
結構可以有實例構造函數和靜態構造函數,但不允許有析構函數。
實例構造函數
語言隱式地為每個結構提供一個無參構造函數。這個構造函數把結構的每個成員設置為該類型的默認值。值成員設置成它們的默認值,引用成員設置為null。
例:帶參數的構造函數
struct Simple { public int X; public int Y; public Simple(int a,int b) { X=a; Y=b; } } class Program { static void Main() { var s1=new Simple(); var s2=new Simple(4,10); Console.WriteLine("{0},{1}",s1.X,s1.Y); Console.WriteLine("{0},{1}",s2.X,s2.Y); } }
也可以不是用new運算符創建結構實例,然而這樣做,有一些限制:
- 在顯式設置數據成員后,才能使用它們的值
- 在對所有數據成員賦值后,才能調用任何函數成員
例:不用new創建結構實例
struct Simple { public int X; public int Y; } class Program { static void Main() { Simple s1,s2; Console.WriteLine("{0},{1}",s1.X,s1.Y); //編譯錯誤 ↑ ↑ 還未賦值 s2.X=5; s2.Y=10; Console.WriteLine("{0},{1}",s2.X,s2.Y); //沒錯誤 } }
靜態構造函數
與類相似,結構的靜態構造函數創建並初始化靜態數據成員,而且不能引用實例成員。
以下兩種行為發生前,會調用靜態構造函數
- 調用顯式聲明的構造函數
- 引用結構的靜態成員
構造函數和析構函數小結
字段初始化語句是不允許的
在結構中字段初始化語句是不允許的。
struct Simple { public int x=10; //編譯錯誤 public int y=10; //編譯錯誤 }
結構是密封的
結構總是隱式密封的,因此,不能從它們派生其他結構。
結構不支持繼承,所以下列修飾符不能用於結構聲明:
- protected
- internal
- abstract
- virtual
結構都派生自System.ValueType,System.ValueType派生自object。
兩個可以用於結構成員並與繼承相關的關鍵字是new和override,當創建一個和基類System.ValueType的成員有相同名稱的成員時使用它們。
裝箱和拆箱
如同其他值類型數據,如果想將一個結構實例作為引用類型對象,必須創建裝箱(boxing)副本。裝箱的過程就是制作值類型變量的引用類型副本。裝箱和拆箱(unboxing)在第16章詳述。
6個重要的.NET概念: - 堆棧,堆,值類型,引用類型,裝箱和拆箱
結構作為返回值和參數
結構可以作為返回值和參數
- 返回值 當結構作為返回值時,將創建它的副本並從函數成員返回
- 值參數 當結構作為值參數時,將創建實參結構的副本。該副本用於方法的執行中
- ref和out參數 若把一個結構用作ref或out參數,傳入方法的是結構的引用,這樣就可以修改其數據成員
關於結構的其他信息
對於結構進行分配比創建類的實例開銷小,所以使用結構替代類有時可以提高性能,但要注意到裝箱和拆箱的高代價。
關於結構,需要知道的最后一些事情如下:
- 預定義簡單類型(int、short、long等等),盡管在.NET和C#中被視為原始類型,它們實際上在.NET中都實現為結構
- 可以使用與聲明分部類相同的方法聲明分部結構,如第6章所述。
結構和類一樣,可以實現接口。接口將在第15章闡述。