兩類欄位比較
| 特性 | 靜態欄位 (static) | 實例欄位 |
| 所屬 | 類別本身 | 具體物件實例 |
| 存取方式 | 類別名.欄位 | 實例.欄位 |
| 記憶體位置 | 靜態資料區(High Frequency Heap) | 受控堆疊物件內部 |
| 生命週期 | 應用程式域存活期間 | 隨實例建立/銷毀 |
| 共享性 | 所有實例共享同一份 | 每個實例獨立副本 |
基本宣告與存取
class Demo
{
private static int _staticCount = 0; // 靜態欄位
private int _instanceCount = 0; // 實例欄位
static void Main()
{
Demo a = new Demo();
Console.WriteLine(a._instanceCount); // 0
Console.WriteLine(Demo._staticCount); // 0
}
}
readonly:執行期常數
- 可在宣告處或建構函式中指派,之後不可變更。
- 適用於執行期才能決定的不變值(如從設定檔讀取、依注入物件)。
- 不同於
const(編譯期常數,必須為實值型別或字串,IL 直接內嵌)。
class Config
{
private readonly string _connStr;
private readonly int _maxRetry = 3; // 宣告指派
public Config(string connStr)
{
_connStr = connStr; // 建構函式指派(唯一可修改處)
// _maxRetry = 5; // 編譯錯誤:readonly 欄位只能在建構函式指派
}
}
靜態 readonly 與 const 差異
class Constants
{
public const double PI = 3.14159; // 編譯期常數,IL 直接內嵌
public static readonly double E = 2.71828; // 執行期常數,執行時讀取欄位
}
const:跨組件參考時,值會內嵌至呼叫端 IL,修改需重新編譯所有參考者。
static readonly:修改定義端重新編譯即可,參考端自動取得新值,適合公開 API 的常數。
記憶體模型補充
- 靜態欄位儲存於類別的 MethodTable 相關結構(High Frequency Heap),由 EEClass 管理。
- 實例欄位緊隨著物件標頭(SyncBlockIndex + MethodTable 指標)排列於受控堆疊。
readonly 由 CLR 在 JIT/驗證層面強制,非語法糖;嘗試透過反射修改會擲回 FieldAccessException。