C#結構體struct -0029
阿新 • • 發佈:2020-06-20
結構體
有時候我們僅需要一個小的資料結構,類提供的功能多於我們需要的功能;考慮到效能原因,最好使用結構體。
結構體是值型別,儲存在棧中或儲存為內聯(如果結構體是儲存在堆中的另一個物件的一部分)。
例如類class:
public class Dimensions { public Dimensions(double length,double width) { Length = length; Width = width; } public double Length { get; set; } public double Width { get; set; } }
可以使用結構體struct替換:
public struct Dimensions { public Dimensions(double length,double width) { Length = length; Width = width; } public double Length { get; set; } public double Width { get; set; } }
也可以為結構體struct建立函式,和給類建立函式完全相同:
public struct Dimensions { public Dimensions(doublelength,double width) { Length = length; Width = width; } public double Length { get; set; } public double Width { get; set; } public double Diagonal => Math.Sqrt(Length * Length + Width * Width); }
結構體初始化
結構體是值型別,但在使用時的語法和類基本一模一樣。例如對於上面定義的類或結構體,均可使用程式碼:
Dimensions point = new Dimensions(3,6);
注意:
因為結構體是值型別,所以new運算子與類和其他引用型別的工作方式不同。
用於結構體struct的new運算子並不分配堆中的記憶體,而是隻呼叫相應的建構函式,根據傳送給它的引數,初始化所有欄位。
對於結構,變數宣告實際上是韋整個結構在棧中分配空間。例如用如下語法(如果是類的話,就會編譯錯誤):
Dimensions point; //直接省略new point.Length = 3; point.Width = 6;
結構體遵循其他資料型別都遵守的規則:在使用前所有元素都必須進行初始化。
結構體的初始化方法:
- 使用new運算子
- 給所有的欄位直接賦值
結構體效能影響
- 為結構體分配記憶體時,速度非常快,因為它們將內聯或者儲存在棧中。結構體超出作用域被刪除時,速度也很快,不需要等待垃圾收集。
- 如果把結構體作為引數來傳遞,或者把一個結構體賦值給另一個結構體,結構體的所有內容就會被複制;這樣就會有效能損失。這也是為什麼結構體主要用於小的資料結構。
- 把結構體作為引數傳遞給方法時,應該把它作為ref引數傳遞 - 此時只傳遞了結構體在記憶體中地址。
只讀結構體
C#7.2開始,readonly修飾符可以應用於結構體struct,因此編譯器保證結構體的不變性。
public readonly struct Dimensions { public Dimensions(double length,double width) { Length = length; Width = width; } public double Length { get; } public double Width { get; } public double Diagonal => Math.Sqrt(Length * Length + Width * Width); }
對於readonly修飾符,如果在建立物件後型別更改了欄位或屬性,編譯器就會報錯。
使用readonly編譯器可以生成優化的程式碼,使其在傳遞結構體時不會複製結構體的內容;
相反,編譯器使用引用,因為它永遠不會改變。
注意:上面readonly結構體的屬性是隻讀的,只有get;如果有set的話,編譯會報錯:
error CS8341: Auto-implemented instance properties in readonly structs must be readonly.