C#中結構體與類的區分
在類的使用過程中,既不需要很多方法,也不需要從類中繼承,為了提升效能,可以使用結構體來替代類。
與類不同的是,結構體用struct 修飾;結構體中的例項欄位不能自定義預設值,而類可以,編譯器會隱式的給出結構體和類的預設建構函式,但是結構體的預設構造不能顯示給出,不然編譯器會報錯,當類有自定義的建構函式時,預設構造會被隱藏,要想使用預設構造,必須顯示給出;結構體的自定義建構函式必須初始化所有的例項欄位和未初始化的屬性,而類不必。下面通過例子介紹結構體與類的區分,如下所示:
public class AA { // 類中的欄位可以自定義預設值,也可以只宣告 public int a = 1; // 只宣告的欄位 public int b; public int D{get;} // 預設構造方法 public AA() { } // 自定義構造方法,可以不用初始化沒有自定義預設值的欄位和屬性 public AA(int x) { } } public struct BB { // 例項欄位,不能在宣告的時候給出預設值 public int a; // 靜態欄位,外界可以通過結構體名訪問,可以自定義預設值,如果沒給,系統預設值0。 public static int b = 10; // 屬性,有預設返回值 public int C{get{return 1;}} // 屬性,沒有預設返回值 public int D{get;} // 靜態屬性 public static int E{get;} // 自定義的構造方法,必須初始化所有沒有自定義預設值的欄位和屬性 public BB(int x) { a = 1; D = x; } public void Test() { // 在結構體內部(類也可以)可以使用只宣告沒有自定義預設值的欄位或屬性,結果是該型別的預設值 int f = a; f = D; } }
由於結構體是值型別,所以在宣告的時候系統就已經為他分配棧上的記憶體了,而 new 運算子只是呼叫結構體的建構函式去初始化結構體中的欄位和屬性。此時可以給該結構體的例項欄位賦值,但是在使用該欄位的值(比如,賦值給其他變數,用作方法的引數)之前必須要進行初始化(1、呼叫建構函式 2、給該欄位先賦值)。下面給出呼叫的示例:
public class Test { public Test() { // 宣告一個 BB 結構體型別的變數 bb,這是一個區域性變數,使用他的例項欄位之前要初始化 BB bb; // int c = bb.a; bb.a 沒有初始化,這樣會報錯 bb.a = 1; int c = bb.a; } } public class Test1 { // 宣告一個 BB 結構體型別的變數 bb,系統會預設呼叫該結構體的預設建構函式進行初始化(相當於:BB bb = new BB()) BB bb; public Test1() { //這樣不會報錯,bb 已經有預設初始化 int c = bb.a; } }
結構體與類的不同點總結:
1、結構體是值型別,儲存在棧上,類是引用型別,儲存在託管堆上,結構體在宣告的時候就已經為其分配棧上的記憶體了,而類需要用 new為其分配堆上面的記憶體;
2、結構體是隱式密封的,不能用 sealed 和 abstract 修飾,結構體不能被繼承,類可以被繼承;
3、結構體中的例項欄位只能宣告,不能賦值,而類沒有限制,結構體只宣告沒有用 new 進行初始化時,可以給他的例項欄位賦值,而類不行;
4、結構體沒有解構函式,結構體中的方法不能用 virtual 和 abstract 修飾,但是可以用 override 修飾,用來重寫父類的方法;
4、結構體不能顯示給出預設建構函式(無引數的構造),無論有沒有自定義構造,預設構造都隱式存在,而類中有自定義建構函式時,預設構造會被隱藏,要想呼叫預設構造,必須顯示給出預設構造。
5、結構體的自定義建構函式必須初始化所有的例項欄位和沒有初始化的非靜態屬性,類沒有限制。
結構體和類的靜態建構函式:點選開啟連結