建構子基本規則
- 名稱必須與類別同名 (大小寫敏感)。
- 不可宣告回傳型別 (連
void 都不能寫)。
- 通常
public;private/internal 用於單例、工廠、抽象基類別。
- 不可被繼承,衍生類別必須自行定義並呼叫
base(...)。
預設建構子與隱含 base()
// 這兩個類別等價
class A { }
class A {
public A() : base() { } // 編譯器自動產生
}
// 如果基類別沒有無參數建構子
class Base { public Base(int x) { } }
class Derived : Base {
// 錯誤 CS1729: 必須顯式呼叫 base(int)
public Derived() { }
// 正確
public Derived(int x) : base(x) { }
}
建構子鏈:this(...) 委派模式
public class Connection {
public string Host { get; }
public int Port { get; }
public TimeSpan Timeout { get; }
public string User { get; }
public string Password { get; }
// 主要建構子:參數最完整
public Connection(string host, int port, TimeSpan timeout, string user, string password) {
Host = host; Port = port; Timeout = timeout; User = user; Password = password;
}
// 便利建構子:委派給主要建構子
public Connection(string host, int port, string user, string password)
: this(host, port, TimeSpan.FromSeconds(30), user, password) { }
public Connection(string host, int port)
: this(host, port, "guest", "guest") { }
}
this(...) 必須是建構子第一條陳述式。
- 避免循環委派 (編譯器偵測 CS0161)。
- 減少重複代碼,確保初始化邏輯單一來源。
建構子設計規範與反模式
| 規範 | 說明 | 反模式 |
| 僅做初始化 | 欄位/屬性賦值、參數驗證 | 呼叫虛擬方法、啟動執行緒、IO 操作、註冊事件 |
| 參數驗證盡早 | if (arg == null) throw new ArgumentNullException(...); | 延遲到方法中才驗證 |
| 不可變物件 | 唯讀欄位/init 屬性,建構子完整初始化 | 建構後再大量設定屬性 |
| 避免過多多載 | 超過 3-4 個考慮 Builder/Factory | 10+ 個建構子多載難以維護 |
靜態建構子 vs 實例建構子
class Config {
static Config() { // 靜態建構子
LoadFromFile(); // 類別首次存取前執行一次
}
public Config() { // 實例建構子
// 每次 new 都執行
}
}
- 靜態建構子:無參數、無存取修飾詞、每個程式域最多執行一次、執行緒安全。
- 實例建構子:可多載、有參數、每次實例化執行。
結構體建構子特殊規則
- 結構體不可定義無參數建構子 (CLR 保證零值初始化)。
- C# 10+ 允許定義有參數建構子,但必須初始化所有欄位。
struct Point { public int X, Y; public Point(int x, int y) { X = x; Y = y; } }
現代 C# 簡化建構子語法
// C# 12 主要建構子
public class Person(string Name, int Age) {
public string Name { get; } = Name;
public int Age { get; } = Age;
public void Greet() => Console.WriteLine($"Hi, {Name} ({Age})");
}
// 等同於傳統寫法但更簡潔
var p = new Person("Alice", 30);