「靜態」是 C# 中最基礎卻也最常被誤解的關鍵字。本文從記憶體模型、存取規則、設計模式三個維度,系統性釐清 static 的行為邊界與最佳實踐。
| 維度 | 靜態成員 | 實例成員 |
|---|---|---|
| 所屬對象 | 類型本身 | 具體物件實例 |
| 記憶體位置 | High-Frequency Heap (類型物件) | Managed Heap (每個實例獨立) |
| 生命週期 | AppDomain 存活期間 | 隨實例 GC 回收 |
| 存取方式 | TypeName.Member | instance.Member |
| 共享特性 | 全程式單一份複本 | 每實例獨立複本 |
public class Demo
{
public static int StaticField = 1;
public int InstanceField = 2;
public static void StaticMethod()
{
Console.WriteLine(StaticField); // ✓ 直接存取靜態欄位
// Console.WriteLine(InstanceField); // ✗ 編譯錯誤:無 this 參考
// 間接存取實例成員:必須先 new 實例
var obj = new Demo();
Console.WriteLine(obj.InstanceField); // ✓
}
public void InstanceMethod()
{
Console.WriteLine(StaticField); // ✓ 實例方法可直接存取靜態
Console.WriteLine(InstanceField); // ✓ 直接存取實例欄位
StaticMethod(); // ✓ 直接呼叫靜態方法
}
}

圖示驗證:靜態方法內 new Demo().ObjectFunc() 可間接觸發實例方法,且實例方法共享同一份程式碼區塊 (Code Heap),不隨實例數量增減。
public class Config
{
public static readonly string ConnectionString;
public static readonly int MaxRetry;
// 僅執行一次,執行緒安全,在第一次存取任何靜態成員前自動觸發
static Config()
{
ConnectionString = ConfigurationManager.ConnectionStrings["DB"].ConnectionString;
MaxRetry = int.Parse(ConfigurationManager.AppSettings["MaxRetry"]);
}
}
beforefieldinit 影響)public static class MathExtensions
{
// 編譯器強制:所有成員必須 static
public static double StdDev(this IEnumerable<double> source) { ... }
public static T Median<T>(this IEnumerable<T> source) where T : struct { ... }
}
sealed,不可繼承new 編譯報錯static 建構函數FileHelper, JsonSerializer, GuardStringExtensions, EnumerableExtensionsAppConstants// .NET 4+ 建議:Lazy<T> 執行緒安全、延遲初始化
public sealed class Logger
{
private static readonly Lazy<Logger> _instance =
new Lazy<Logger>(() => new Logger());
public static Logger Instance => _instance.Value;
private Logger() { }
}
public interface IPaymentStrategy { void Pay(decimal amount); }
public static class PaymentFactory
{
private static readonly Dictionary<string, IPaymentStrategy> _strategies
= new Dictionary<string, IPaymentStrategy>(StringComparer.OrdinalIgnoreCase)
{
["alipay"] = new AlipayStrategy(),
["wechat"] = new WechatStrategy()
};
public static IPaymentStrategy Get(string name)
=> _strategies.TryGetValue(name, out var s) ? s : throw new ArgumentException($"Unknown: {name}");
}
public static class FluentBuilder
{
public static HtmlBuilder Div(this HtmlBuilder b, Action<HtmlBuilder> act)
{ act(b); return b; }
public static HtmlBuilder Class(this HtmlBuilder b, string cls)
{ b.Attributes["class"] = cls; return b; }
}
// 使用:builder.Div(b => b.Class("container").Div(...))
| 陷阱 | 後果 | 解法 |
|---|---|---|
| 靜態集合當作快取未清理 | 記憶體洩漏、資料過期 | 用 MemoryCache / ConcurrentDictionary + 定時清理 |
| 靜態建構函數拋出例外 | 類型永久不可用 | 改用靜態工廠方法 Create() 手動控制初始化 |
| 多執行緒並發修改靜態可變狀態 | 競態條件、資料損毀 | lock、Interlocked、ImmutableCollections |
| 靜態類過度膨脹成「上帝類」 | 耦合度高、難測試 | 拆分為多個靜態類、改用 DI 容器管理服務 |
static fieldstatic methodstatic class理解 static 的本質是「綁定於類型而非實例」,善用其共享特性簡化無狀態邏輯,警惕其全域狀態帶來的耦合與測試困難,方能在架構設計中遊刃有餘。