常數 是編譯後不可變更的固定值。C# 提供 const (編譯期常數) 與 readonly (執行期常數) 兩種機制,另有字面值、列舉常數。正確選擇能確保效能、版本相容性與語意正確。
const:編譯期常數const 欄位/區域變數在編譯期確定值,IL 中直接內嵌常數值:
public const double PI = 3.141592653589793;
public const int MaxRetries = 3;
public const string AppName = "MyApp";
// 區域常數
const int BufferSize = 4096;
// 必須初始化,且初始化運算式必須為編譯期常數
// const DateTime Now = DateTime.Now; // 錯誤:非編譯期常數
// const int[] Arr = {1,2,3}; // 錯誤:陣列非常數
static,不可標示 staticbool、byte、sbyte、short、ushort、int、uint、long、ulong、char、float、double、decimal、string、enum、null (參考型別僅限 null)readonly:執行期常數readonly 欄位在建構子或宣告處初始化,之後不可變更:
public class Config {
// 宣告初始化
public readonly string Version = "1.0.0";
// 建構子初始化 (可依參數決定)
public readonly int MaxConnections;
public readonly DateTime StartupTime;
public Config(int maxConn) {
MaxConnections = maxConn;
StartupTime = DateTime.UtcNow; // 執行期取得
}
// readonly 靜態欄位:靜態建構子初始化
public static readonly string ConnectionString;
static Config() {
ConnectionString = LoadFromConfigFile(); // 複雜初始化
}
}
| 場景 | 選擇 | 原因 |
|---|---|---|
| 數學常數 (PI, E) | const | 永不變更、編譯期可知、效能最佳 |
| 應用程式版本號 | readonly | 建置時期注入、可能更新 |
| 資料庫連線字串 | readonly | 執行期從設定檔讀取 |
| 介面中的常數 | const | 介面不支援 readonly 欄位 (C# 8 前) |
| 屬性參數 | const | 屬性建構子需編譯期常數 |
| 大型陣列/集合 | readonly | const 不支援陣列 |
| 跨組件共用、可能變更 | readonly | 避免重新編譯消費者 |
int dec = 42;
uint u = 42U;
long l = 42L;
ulong ul = 42UL;
long hex = 0x2A; // 十六進位
long bin = 0b101010; // 二進位 (C# 7+)
int underscore = 1_000_000; // 數字分隔符 (C# 7+)
// 後綴大小寫皆可:42u 42U 42l 42L
double d = 3.14;
float f = 3.14F; // F/f 後綴
decimal m = 3.14M; // M/m 後綴
double sci = 1.23e-4; // 科學記號
double hexFloat = 0x1.921fb54442d18p+1; // 十六進位浮點 (C# 11+)
char c = 'A';
char newline = '\n';
char unicode = '\u0041'; // Unicode 逸出
char hexChar = '\x41'; // 十六進位
string s1 = "Hello";
string s2 = @"C:\Path\File"; // 逐字字串:不處理逸出、可跨行
string s3 = $"{DateTime.Now}"; // 插值字串
// 逐字字串雙引號逸出
string quote = @"""Hello"""; // "Hello"
列舉成員本質為編譯期常數,底層為整數型別:
public enum HttpStatus : int {
OK = 200,
NotFound = 404,
ServerError = 500
}
// 使用如常數
int code = HttpStatus.OK; // 200
// switch 窮盡性檢查
string msg = status switch {
HttpStatus.OK => "成功",
HttpStatus.NotFound => "找不到",
_ => "其他"
};
readonly struct 與 init 存取子// C# 9+ init 存取子:物件初始化器可設定,之後不可變
public class Settings {
public string ApiKey { get; init; }
public int Timeout { get; init; }
}
// 使用
var s = new Settings { ApiKey = "key", Timeout = 30 };
// s.ApiKey = "new"; // 編譯錯誤
required 成員// C# 11+:建構/初始化時必須提供
public class User {
public required string Email { get; init; }
public required string Name { get; init; }
}
var u = new User { Email = "a@b.com", Name = "Alice" };
[SomeAttribute(MaxRetries)] // 需 const
public class MyClass { }
const int MaxRetries = 3; // 編譯期常數
PascalCase (public/protected),camelCase (private/區域)。static class 或 enum 組織。const/readonly 命名。1_000_000 提升可讀性。A: 編譯器將常數值直接寫入呼叫端 IL。定義組件修改 const 值重新編譯,呼叫端若不重新編譯仍使用舊值。
A: 不可以。readonly 欄位只能在宣告或建構子初始化。用 init 存取子 (屬性) 支援物件初始化器。
A: 參考型別 const 僅能為 null:const string Empty = null;。實值型別不可為 null。
A: 僅由字面值、const 變數、基本運算子 (+ - * / % << >> & | ^ ~)、轉型、sizeof、預設值運算子組成的運算式。