| 特性 | 靜態方法 | 非靜態方法 |
|---|---|---|
| 呼叫方式 | 類別名.方法() | new 類別().方法() |
| 所屬對象 | 類別本身 | 具體實例 |
| 記憶體 | 單一份程式碼段、靜態資料段 | 每實例獨立資料、共享程式碼 |
this 關鍵字 | 不可用 | 指向當前實例 |
| 存取成員 | 僅靜態成員 | 靜態+非靜態皆可 |
| 生命週期 | 應用程式域存活期 | 實例存活期(GC回收) |
| 執行緒安全 | 需自行鎖定 | 實例隔離天然較安全 |
[Managed Heap] ├─ Type Object (MethodTable) ──→ 靜態方法程式碼 (共享) │ ├─ 靜態欄位 │ └─ 非靜態方法槽位 │ ├─ Instance #1 ──→ 非靜態欄位 ├─ Instance #2 ──→ 非靜態欄位 └─ Instance #3 ──→ 非靜態欄位
using System;
namespace ConsoleApp {
class MathUtil {
public static double PI = 3.14159; // 靜態欄位
private static int _callCount = 0; // 靜態私有欄位
// 靜態方法
public static double CircleArea(double r) {
_callCount++;
return PI * r * r;
}
// 非靜態方法
private double _lastRadius;
public double CircleAreaInstance(double r) {
_lastRadius = r;
return PI * r * r;
}
public static int GetCallCount() => _callCount;
}
class Program {
static void Main() {
// 靜態呼叫
Console.WriteLine(MathUtil.CircleArea(5)); // 78.53975
Console.WriteLine(MathUtil.CircleArea(10)); // 314.159
Console.WriteLine(MathUtil.GetCallCount()); // 2
// 非靜態呼叫
var util1 = new MathUtil();
var util2 = new MathUtil();
Console.WriteLine(util1.CircleAreaInstance(5)); // 78.53975
Console.WriteLine(util2.CircleAreaInstance(5)); // 78.53975 (各自獨立 _lastRadius)
}
}
}
public sealed class ConfigManager {
private static readonly Lazy _instance =
new Lazy(() => new ConfigManager());
public static ConfigManager Instance => _instance.Value;
private ConfigManager() { /* 私有建構子 */ }
public string GetConnectionString() => "Server=...";
// 靜態工廠方法
public static ConfigManager CreateForTesting() => new ConfigManager();
}
var sw = Stopwatch.StartNew();
for (int i = 0; i < 10_000_000; i++) MathUtil.CircleArea(5);
sw.Stop();
Console.WriteLine($"Static: {sw.ElapsedMilliseconds} ms");
sw.Restart();
var util = new MathUtil();
for (int i = 0; i < 10_000_000; i++) util.CircleAreaInstance(5);
sw.Stop();
Console.WriteLine($"Instance: {sw.ElapsedMilliseconds} ms");
// 典型結果:Static ~120ms, Instance ~150ms (差異微小,JIT優化後幾乎相同)
結論:靜態方法呼叫略快但差異可忽略,選擇依據應為設計需求而非效能。
staticstatic + 鎖定readonly、Lazy<T>、ConcurrentDictionarystatic 類別 + this 參數,語法糖不改變本質
class HeavyResource {
private static readonly ExpensiveObject _resource;
// 靜態建構子:型別首次使用前自動執行一次,執行緒安全
static HeavyResource() {
_resource = new ExpensiveObject(); // 可能耗時、拋例外
}
public static void Use() => _resource.DoWork();
}
靜態方法屬於類別、非靜態屬於實例。選擇原則:「是否需要物件狀態」。無狀態工具→靜態;有狀態行為→實例。效能差異微乎其微,可維護性與測試性才是決策關鍵。