執行個體建構函式 (C# 程式設計手冊)

您可以宣告執行個體建構函式,指定當您使用new 運算式建立型別的新執行個體時所執行的程式碼。 若要在非靜態類別中初始化靜態類別或靜態變數,您可以定義靜態建構函式

如下列範例所示,您可以在一種類型中宣告數個執行個體建構函式:

class Coords
{
    public Coords()
        : this(0, 0)
    {  }

    public Coords(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public override string ToString() => $"({X},{Y})";
}

class Example
{
    static void Main()
    {
        var p1 = new Coords();
        Console.WriteLine($"Coords #1 at {p1}");
        // Output: Coords #1 at (0,0)

        var p2 = new Coords(5, 3);
        Console.WriteLine($"Coords #2 at {p2}");
        // Output: Coords #2 at (5,3)
    }
}

在上述範例中,第一個無參數建構函式會呼叫兩個引數相等 0 的第二個建構函式。 若要這麼做,請使用 this 關鍵字。

當您在衍生類別中宣告執行個體建構函式時,可以呼叫基底類別的建構函式。 若要這樣做,請使用 base 關鍵字,如下列範例所示:

abstract class Shape
{
    public const double pi = Math.PI;
    protected double x, y;

    public Shape(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public abstract double Area();
}

class Circle : Shape
{
    public Circle(double radius)
        : base(radius, 0)
    {  }

    public override double Area() => pi * x * x;
}

class Cylinder : Circle
{
    public Cylinder(double radius, double height)
        : base(radius)
    {
        y = height;
    }

    public override double Area() => (2 * base.Area()) + (2 * pi * x * y);
}

class Example
{
    static void Main()
    {
        double radius = 2.5;
        double height = 3.0;

        var ring = new Circle(radius);
        Console.WriteLine($"Area of the circle = {ring.Area():F2}");
        // Output: Area of the circle = 19.63
        
        var tube = new Cylinder(radius, height);
        Console.WriteLine($"Area of the cylinder = {tube.Area():F2}");
        // Output: Area of the cylinder = 86.39
    }
}

無參數建構函式

如果 類別 沒有明確的執行個體建構函式,C# 會提供無參數建構函式,讓您可用來具現化該類別的執行個體,如下列範例所示:

public class Person
{
    public int age;
    public string name = "unknown";
}

class Example
{
    static void Main()
    {
        var person = new Person();
        Console.WriteLine($"Name: {person.name}, Age: {person.age}");
        // Output:  Name: unknown, Age: 0
    }
}

該建構函式會根據對應的初始設定式,初始化執行個體欄位和屬性。 如果欄位或屬性沒有初始設定式,其值會設定為欄位或屬性類型的 預設值 。 如果您在類別中宣告至少一個執行個體建構函式,C# 不會提供無參數建構函式。

結構類型一律提供無參數建構函式。 無參數建構函式是產生類型預設值或明確宣告無參數建構函式的隱含無參數建構函式。 如需詳細資訊,請參閱結構型別一文中的結構初始化和預設值一節。

主要建構函式

從 C# 12 開始,您可以在類別和結構中宣告主要建構函式。 您可以將任何參數放在類型名稱之後的括號中:

public class NamedItem(string name)
{
    public string Name => name;
}

主要建構函式的參數位於宣告類型整個主體的範圍內。 它們可以初始化屬性或欄位。 它們可以當做方法或區域函式中的變數使用。 它們可以傳遞至基底建構函式。

主要建構函式表示類型的任何執行個體都需要這些參數。 任何明確撰寫的建構函式都必須使用 this(...) 初始設定式語法叫用主要建構函式。 這可確保所有建構函式絕對會指派主要建構函式參數。 對於任何 class 型別,包括 record class 類別,當主要建構函式存在時,不會發出隱含無參數建構函式。 對於任何 struct 型別,包括 record struct 類別,一律會發出隱含無參數建構函式,並且一律初始化所有欄位,包括主要建構函式參數到 0 位模式。 如果您撰寫明確的無參數建構函式,則必須叫用主要建構函式。 在此情況下,您可以為主要建構函式參數指定不同的值。 下列程式碼顯示主要建構函式的範例。

// name isn't captured in Widget.
// width, height, and depth are captured as private fields
public class Widget(string name, int width, int height, int depth) : NamedItem(name)
{
    public Widget() : this("N/A", 1,1,1) {} // unnamed unit cube

    public int WidthInCM => width;
    public int HeightInCM => height;
    public int DepthInCM => depth;

    public int Volume => width * height * depth;
}

您可以透過在屬性上指定 method: 目標,為合成的主要建構函式方法新增屬性:

[method: MyAttribute]
public class TaggedWidget(string name)
{
   // details elided
}

如果您未指定 method 目標,屬性會置放於類別上,而不是方法上。

classstruct 類型中,主要建構函式參數可在型別主體中的任何位置使用。 它們可以當做成員欄位使用。 使用主要建構函式參數時,編譯器會在具有編譯器產生名稱的私人欄位中擷取建構函式參數。 如果類型主體中未使用主要建構函式參數,則不會擷取任何私用欄位。 該規則可防止意外配置傳遞至基底建構函式的主要建構函式參數的兩個複本。

如果型別包含 record 修飾元,編譯器會改以合成與主要建構函式參數相同名稱的公用屬性。 對於 record class 型別,如果主要建構函式參數使用與基底主要建構函式相同的名稱,該屬性就是基底 record class 型別的公用屬性。 它不會在衍生 record class 型別中重複。 這些屬性不會針對非 record 型別產生。

另請參閱