首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 方法完全指南:參數傳遞、多型、外部呼叫與版本控制

     編輯:關於C#

前言:方法是類別的行為單元

C# 方法(Member Function)封裝演算法邏輯,分為靜態方法(屬於類型)與實例方法(屬於物件)。本文系統梳理四種參數傳遞模式、方法多載、虛擬/覆寫/密封/抽象繼承機制、外部方法互操作,以及版本控制關鍵字 new/override 的語意差異。

一、四種參數傳遞模式

模式關鍵字語意適用場景
傳值(無)複製實值型別位元 / 參考型別參考預設、輸入參數、不需修改呼叫端變數
傳址ref傳遞變數記憶體位址,雙向同步需修改呼叫端變數(如 Swap)、大型結構體避免複製
輸出out類似 ref,但呼叫端無需初始化,方法內必須指派多重回傳值、TryParse 模式
參數陣列params將零至多個引數封裝為陣列可變參數列表(如 String.Format、Console.WriteLine)

1.1 實值型別 vs 參考型別的傳值陷阱

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 }; } // 修改參考:呼叫端可見

核心原則:傳值傳遞的是「參考的副本」,可修改物件內容,不可替換物件本身。

1.2 out 與 ref 的 IL 差異

  • ref:[In, Out] 屬性,呼叫端必須初始化。
  • out:[Out] 屬性,呼叫端可未初始化,方法內對所有 out 參數必須指派(確定性指派分析)。

1.3 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、泛型數量)。
  • 回傳型別不參與多載解析(編譯錯誤 CS0111)。
  • 解析優先序:精確匹配 > 隱含轉換 > params 擴展 > 泛型推斷。

三、繼承多型:虛擬、覆寫、密封、抽象

3.1 關鍵字語意對照

關鍵字修飾目標繫結時機備註
virtual基類方法執行期允許衍生類覆寫,不可為 static
override衍生類方法執行期必須覆寫 virtual/abstract/override 方法
sealed override衍生類方法執行期覆寫並禁止後續衍生類再次覆寫
abstract基類方法執行期無實作,強制衍生類實作,類別需 abstract
new衍生類方法編譯期隱藏基類同名方法(非多型),會發出警告 CS0108

3.2 經典範例:執行期 vs 編譯期繫結


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"(編譯期繫結)

3.3 密封覆寫 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

3.4 抽象方法可「抽象化」虛擬方法


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++ 隱式覆寫導致的脆弱基類問題。

六、效能與最佳實務

  1. 避免不必要的 ref/out:增加別名分析複雜度,妨礙 JIT 優化。
  2. 熱路徑方法標記 [MethodImpl(MethodImplOptions.AggressiveInlining)]:手動內聯小型方法。
  3. 大型結構體參數:改用 in(C# 7.2+)唯讀傳址,避免複製又保證不修改。
  4. 虛擬方法呼叫開銷:密封類別(sealed class)或密封方法(sealed override)可消除虛擬呼叫間接層。
  5. 非受控呼叫:最小化 P/Invoke 頻率,批次處理;使用 SafeHandle 管理資源生命週期。

結語

方法是 C# 表達行為的核心。精通參數傳遞語意、善用多載簡化 API、正確選擇 virtual/override/sealed/abstract/new 設計穩健繼承體系、謹慎使用 extern 跨越受控邊界,並配合現代 C#(in、ref readonly、required)提升表達力與效能,即能寫出清晰、安全、高效的專業級程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved