屬性是 C# 封裝資料存取的核心機制,兼具欄位的簡潔語法與方法的邏輯控制能力。本文比較三種存取私有欄位的方式,解析屬性 IL 實現、索引器、執行緒安全、參考型別防禦性複製等進階主題。
| 方式 | 封裝性 | 安全性 | 呼叫便利性 | 效能 |
|---|---|---|---|---|
| 改為 public 欄位 | 破壞 | 風險高 | 最簡便 | 最高 |
| 公用 Get/Set 方法 | 保持 | 安全 | 繁瑣 | 最低 |
| 屬性 | 保持 | 安全 | 簡便 | 次高(內聯) |
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
// 自動實作屬性 (C# 3+)
public string Name { get; set; }
// 唯讀自動屬性 (C# 6+)
public string Id { get; } = Guid.NewGuid().ToString();
屬性編譯為 get_Name/set_Name 兩個方法,標記 specialname。JIT 會將其內聯,效能接近直接欄位存取。
public class SampleCollection
{
private readonly List _items = new();
public string this[int index]
{
get => _items[index];
set => _items[index] = value;
}
// 多參數索引器
public string this[int row, int col] { get; set; }
}
private readonly object _lock = new();
private string _name;
public string Name
{
get { lock(_lock) return _name; }
set { lock(_lock) _name = value; }
}
透過顯性介面實作,同一類別可提供唯讀與可寫兩種版本(不建議常用,易混淆)。
// 錯誤:呼叫端可修改內部 _data
public class Wrapper
{
private Inner _data = new();
public Inner Data => _data; // 回傳參考
}
// 正確:回傳副本或不可變介面
public class Wrapper
{
private Inner _data = new();
public Inner Data => _data.Clone(); // 實作 ICloneable
// 或回傳介面
public IInnerReadOnly Data => _data;
}
private int _age;
public int Age
{
set
{
if (value < 0 || value > 150) throw new ArgumentOutOfRangeException();
_age = value;
}
}
屬性是 C# 封裝的最佳實踐:語法簡潔、效能優異、支援完整邏輯控制。掌握索引器、執行緒安全、防禦性複製等進階技巧,能設計出健壯且易用的 API。團隊應建立屬性設計規範(如:預設私有 setter、參考型別回傳副本、Set 必驗證)。