C# 方法(Member Function)封裝演算法邏輯,分為靜態方法(屬於類型)與實例方法(屬於物件)。本文系統梳理四種參數傳遞模式、方法多載、虛擬/覆寫/密封/抽象繼承機制、外部方法互操作,以及版本控制關鍵字 new/override 的語意差異。
| 模式 | 關鍵字 | 語意 | 適用場景 |
|---|---|---|---|
| 傳值 | (無) | 複製實值型別位元 / 參考型別參考 | 預設、輸入參數、不需修改呼叫端變數 |
| 傳址 | ref | 傳遞變數記憶體位址,雙向同步 | 需修改呼叫端變數(如 Swap)、大型結構體避免複製 |
| 輸出 | out | 類似 ref,但呼叫端無需初始化,方法內必須指派 | 多重回傳值、TryParse 模式 |
| 參數陣列 | params | 將零至多個引數封裝為陣列 | 可變參數列表(如 String.Format、Console.WriteLine) |
class Element { public int Number; }
void ChangeVal(Element e) { e.Number = 100; } // 修改物件內容:呼叫端可見
void ChangeRef(Element e) { e = new Element { Number = 100 }; } // 修改參考本身:呼叫端不可見
void ChangeRefRef(ref Element e) { e = new Element { Number = 100 }; } // 修改參考:呼叫端可見
核心原則:傳值傳遞的是「參考的副本」,可修改物件內容,不可替換物件本身。
out 與 ref 的 IL 差異ref:[In, Out] 屬性,呼叫端必須初始化。out:[Out] 屬性,呼叫端可未初始化,方法內對所有 out 參數必須指派(確定性指派分析)。params 陣列的隱含轉換
int Sum(params int[] numbers) => numbers.Sum();
Sum(1, 2, 3); // 隱含建立 int[] {1,2,3}
Sum(new int[] {1,2}); // 顯式陣列
Sum(); // 空陣列
ref/out/params、泛型數量)。params 擴展 > 泛型推斷。| 關鍵字 | 修飾目標 | 繫結時機 | 備註 |
|---|---|---|---|
virtual | 基類方法 | 執行期 | 允許衍生類覆寫,不可為 static |
override | 衍生類方法 | 執行期 | 必須覆寫 virtual/abstract/override 方法 |
sealed override | 衍生類方法 | 執行期 | 覆寫並禁止後續衍生類再次覆寫 |
abstract | 基類方法 | 執行期 | 無實作,強制衍生類實作,類別需 abstract |
new | 衍生類方法 | 編譯期 | 隱藏基類同名方法(非多型),會發出警告 CS0108 |
class Base { public virtual void G() => Console.WriteLine("Base.G"); }
class Derived : Base { public override void G() => Console.WriteLine("Derived.G"); }
Base b = new Derived();
b.G(); // 輸出 "Derived.G" —— 執行期繫結(虛擬方法)
// 若 Derived 使用 new public void G() 則輸出 "Base.G"(編譯期繫結)
sealed override 防止繼承鏈破壞
class A { public virtual void F() { } }
class B : A { public sealed override void F() { } } // 封鎖 F
class C : B { public override void F() { } } // 編譯錯誤 CS0239
class Base { public virtual void M() { } }
abstract class Mid : Base { public abstract override void M(); } // 強制後續衍生類重新實作
class Leaf : Mid { public override void M() { } } // 必須實作
extern 與 P/Invoke
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
extern 告訴編譯器方法實作在非受控 DLL。abstract、virtual、override。DllImport 控制封送行為(CallingConvention、CharSet、SetLastError、ExactSpelling)。new vs override 的設計意圖當基類庫新增虛擬方法,衍生類若已有同名方法:
new 明確隱藏,消除警告,保持二進位相容。override 參與多型,但需確認基類方法確為 virtual。這正是 C# 透過關鍵字強制開發者表達意圖,避免 C++ 隱式覆寫導致的脆弱基類問題。
ref/out:增加別名分析複雜度,妨礙 JIT 優化。[MethodImpl(MethodImplOptions.AggressiveInlining)]:手動內聯小型方法。in(C# 7.2+)唯讀傳址,避免複製又保證不修改。sealed class)或密封方法(sealed override)可消除虛擬呼叫間接層。SafeHandle 管理資源生命週期。方法是 C# 表達行為的核心。精通參數傳遞語意、善用多載簡化 API、正確選擇 virtual/override/sealed/abstract/new 設計穩健繼承體系、謹慎使用 extern 跨越受控邊界,並配合現代 C#(in、ref readonly、required)提升表達力與效能,即能寫出清晰、安全、高效的專業級程式碼。