C#結構體struct -0029

結構體

有時候我們僅需要一個小的數據結構,類提供的功能多於我們需要的功能;考慮到性能原因,最好使用結構體。

結構體是值類型,存儲在棧中或存儲為內聯(如果結構體是存儲在堆中的另一個對象的一部分)。

例如類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(double length, 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.