public readonly struct PhoneList
{
private readonly Phone[] _phones;
public PhoneList(Phone[] phones)
{
_phones = new Phone[phones.Length];
phones.CopyTo(_phones, 0); // 防禦性複製:Phone 為 struct 故複製值
}
public IEnumerator GetEnumerator() => ((IEnumerable)_phones).GetEnumerator();
}
// 使用
var phones = new Phone[10];
// 初始化 phones...
var list = new PhoneList(phones);
phones[5] = Phone.Generate(); // 不影響 list 內部陣列
public Phone[] Phones
{
get
{
var copy = new Phone[_phones.Length];
_phones.CopyTo(copy, 0);
return copy;
}
}
| 模式 | 說明 | 範例 |
|---|---|---|
| 建構函式 | 單次呼叫完整初始化 | new Address("1F", "Taipei", "100") |
| 工廠方法 | 靜態方法封裝建立邏輯 | Color.FromArgb(r,g,b), Color.FromKnownColor |
| 建構器/伴隨類別 | 多步驟建構,最後產出不可變物件 | StringBuilder → string |
public readonly struct Address
{
public string Line1 { get; }
public string Line2 { get; }
public string City { get; }
public string State { get; }
public int ZipCode { get; }
public Address(string line1, string line2, string city, string state, int zipCode)
{
Line1 = line1 ?? throw new ArgumentNullException(nameof(line1));
Line2 = line2 ?? "";
City = city ?? throw new ArgumentNullException(nameof(city));
State = state ?? throw new ArgumentNullException(nameof(state));
ZipCode = zipCode;
ValidateState(state);
ValidateZip(zipCode);
}
// 修改城市 → 回傳新實例
public Address WithCity(string newCity) => new Address(Line1, Line2, newCity, State, ZipCode);
}
var a1 = new Address("111 S. Main", "", "Anytown", "IL", 61111);
// 修改城市
var a2 = a1.WithCity("Ann Arbor"); // a1 不變,a2 為新實例
// 或使用 with 運算式 (C# 9+)
var a3 = a1 with { City = "Ann Arbor", State = "MI", ZipCode = 48103 };
GetHashCode() 穩定,適合 Dictionary、HashSet預設設計不可變實值型別。將複雜物件分解為原子不可變單元(Address、Phone、Name),再組合成較大結構。避免盲目加上 set 存取器,優先考慮 WithXxx() 或 with 運算式回傳新實例。