欄位 vs 屬性:設計哲學對比
| 特性 | 欄位 | 屬性 |
| 本質 | 直接儲存資料的變數 | 封裝邏輯的存取器組合 |
| 封裝性 | 無(直接暴露記憶體位置) | 完全控制讀寫邏輯、驗證、通知 |
| 介面相容性 | 不可定義在介面中 | 可定義在介面中 |
| 繼承多態 | 不可 virtual/override | 支援 virtual/override/abstract |
| 資料繫結 | 不支援 | 完整支援 (WPF/UWP/MAUI/Blazor) |
| 序列化控制 | 困難 | 可自訂忽略/轉換邏輯 |
欄位宣告要點
[attributes] [field-modifiers] 型別 變數名稱;
修飾詞:new, public, protected, internal, private, static, readonly
readonly:只能在宣告或建構子賦值,適合不可變資料。
static:屬於類別,所有實例共享單一儲存位置。
- 預設為
private。
屬性宣告與存取器模式
[attributes] [property-modifiers] 型別 屬性名稱 {
get { return _backingField; }
set { _backingField = value; }
}
修飾詞:new, public, protected, internal, private, static, virtual, sealed, override, abstract
自動實作屬性 (C# 3.0+)
public string Name { get; set; } // 讀寫
public int Age { get; private set; } // 外部唯讀
public Guid Id { get; } = Guid.NewGuid(); // 唯讀,建構子或初始化器賦值
完整屬性模式:驗證與通知
private string _email;
public string Email {
get => _email;
set {
if (_email == value) return;
if (!value.Contains("@")) throw new ArgumentException("Invalid email");
_email = value;
OnPropertyChanged(nameof(Email)); // INotifyPropertyChanged
}
}
唯讀與寫入限制策略
| 需求 | 實作方式 |
| 完全唯讀 | get only / init only (C# 9) |
| 內部可寫、外部唯讀 | public get; private set; |
| 衍生類別可寫、外部唯讀 | public get; protected set; |
| 建構後不可變 | init 存取器 (C# 9 record) |
最佳實務建議
- 公開 API 永遠使用屬性,欄位保持
private。
- 簡單資料容器優先用
record (C# 9) 或 struct 配合自動屬性。
- 避免在屬性
get 執行昂貴運算(資料庫、IO),改用方法(GetSomething())。
- 屬性命名採 PascalCase,布林屬性加
Is/Has/Can 前綴。