const:編譯器將值直接內嵌至呼叫端 IL(ldc.i4),如同硬編碼。
readonly:執行時讀取欄位值(ldsfld),支援任意型別與建構函式初始化。
// 組件 A (Library.dll)
public class Constants
{
public const int MaxRetries = 3; // 編譯時常數
public static readonly int Timeout = 5000; // 執行時常數
}
// 組件 B (App.exe) 參考 A
void Foo()
{
int a = Constants.MaxRetries; // IL 內嵌為 ldc.i4.3
int b = Constants.Timeout; // IL 為 ldsfld 讀取欄位
}
若 A 更新 MaxRetries = 5 但 B 未重新編譯,B 仍使用舊值 3。
readonly 則會在執行時讀取新值,無需重新編譯呼叫端。
// 版本標識使用 const(永不變更)
private const int VERSION_1_0 = 0x0100;
private const int VERSION_2_0 = 0x0200;
// 當前版本使用 readonly(發布時更新)
private static readonly int CurrentVersion = VERSION_2_0;
// 反序列化時比對版本
protected MyType(SerializationInfo info, StreamingContext ctx)
{
int stored = info.GetInt32("VERSION");
switch (stored)
{
case VERSION_2_0: ReadV2(info, ctx); break;
case VERSION_1_0: ReadV1(info, ctx); break;
}
}
// 序列化寫入當前版本
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx)
{
info.AddValue("VERSION", CurrentVersion); // 執行時讀取最新值
}
const 存取略快(直接常數),但差異極微(納秒級)。除非極度效能敏感且值永不變更,否則優先選擇 readonly 的彈性。
| 情境 | 建議 |
|---|---|
| 屬性參數 | const(編譯時需常數) |
| 列舉底層值 | const(隱含) |
| 永不變更的基本型別常數 | const 可接受 |
| 可能隨版本變更的值 | readonly |
| 非基本型別 | readonly(const 不支援) |
| 需在建構函式初始化 | readonly |
| 執行個體層級常數 | readonly(const 隱含 static) |
預設使用 readonly,只有明確理由時才用 const。這能避免版本演進時的靜默錯誤,支援更豐富的型別與初始化邏輯。