首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# readonly vs const 深度比較:編譯期常數與執行期常數的抉擇

     編輯:關於C#

核心差異一覽表

特性const (編譯期常數)readonly (執行期常數)
賦值時機編譯期 (IL 中直接內嵌常值)執行期 (建構子或欄位初始化器)
宣告位置類別欄位、區域變數僅類別欄位 (instance/static)
修飾詞隱含 static,不可加 static可加 static 或 instance
資料型別限制僅基本型別、string、enum、null任意型別 (含 DateTime、自訂類別、陣列等)
初始化彈性宣告時必須給值宣告時或建構子中給值
跨組件版本控制呼叫端編譯時內嵌常值,升級需重新編譯呼叫端呼叫端保留欄位參考,升級組件即時生效
效能極佳 (常值直接內嵌)極佳 (JIT 內聯欄位讀取)

程式碼示範:跨組件版本陷阱


// --- 組件 Lib.dll ---
public class Constants
{
    public const int ConstValue = 100;      // 編譯期常數
    public static readonly int ReadonlyValue = 200; // 執行期常數
}

// --- 組件 App.exe (參考 Lib.dll) ---
public class Consumer
{
    public static int Calc() => Constants.ConstValue + Constants.ReadonlyValue;
    // 編譯後 IL 相當於:ldc.i4.s 100  + ldsfld int32 Constants::ReadonlyValue
}

情境:修改 `Lib.dll` 為 `ConstValue = 300`、`ReadonlyValue = 400`,僅重新部署 Lib.dll,不重新編譯 App.exe。

  • ConstValue:App.exe 仍讀到 100 (已內嵌)。
  • ReadonlyValue:App.exe 讀到 400 (動態欄位存取)。

⚠️ 結論:`const` 適合永不變更的物理/數學常數 (如 `Math.PI`、一天小時數);其餘情況優先用 `readonly` 避免版本控制惡夢。

型別限制實例


// ❌ 編譯錯誤:DateTime 非編譯期常數
public const DateTime Epoch = DateTime.MinValue;

// ✅ 正確:readonly 支援任意型別
public static readonly DateTime Epoch = DateTime.MinValue;
public static readonly int[] Primes = { 2, 3, 5, 7, 11 };
public static readonly MyConfig Config = new MyConfig { Timeout = 30 };

效能微觀分析


// IL 差異
// const:  ldc.i4.s 100          // 直接推常值上堆疊
// readonly: ldsfld int32 ...    // 靜態欄位讀取 (JIT 會內聯為常值傳播)

實測差異 < 1ns,微乎其微。**決策依據應為語意正確性與維護性,非效能。**

最佳實務決策樹

  1. 值絕對不變 (物理常數、協定版本號、固定陣列大小) → const
  2. 值可能調整、或為複雜型別、或需執行期計算 → readonly
  3. 需實例層級常數 (每個實例不同) → readonly (instance field)
  4. 需區域常數 (方法內) → const (區域不支援 readonly)

現代 C# 替代方案

  • static readonly + 屬性模式:對外暴露 `public static int MaxRetry { get; } = 3;` (C# 6+ 唯讀自動屬性)
  • record / record struct (C# 9/10):不可變資料載體,語意更清晰。
  • required init-only 屬性 (C# 11):建構後不可變。

總結

`const` 是**編譯期常值替換**,`readonly` 是**執行期唯讀欄位**。除非是永不變更的基本型別常數,**預設選擇 `readonly`** (或現代不可變語法),能避免跨組件部署陷阱、支援豐富型別、保持語意彈性,是更安全、更專業的選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved