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

深入理解 C# 參數傳遞:值與引用、結構與類的差異

     編輯:關於C語言

前言

C# 方法參數傳遞機制是開發者必須掌握的核心概念。本文系統解析值傳遞與引用傳遞的區別,並深入探討結構與類作為參數時的行為差異,配合代碼示例助你徹底釐清。

一、值參數 vs 引用參數

預設情況下,C# 採用值傳遞:方法接收參數的副本,修改不影響原變數。若需在方法內修改原變數,須使用 ref 或 out 關鍵字進行引用傳遞。

代碼示例

class Program {
    static void Main(string[] args) {
        int arg;

        // 傳值:Main 中的 arg 不會改變
        arg = 4;
        SquareVal(arg);
        Console.WriteLine(arg);  // 輸出: 4

        // 傳引用:Main 中的 arg 會被修改
        arg = 4;
        SquareRef(ref arg);
        Console.WriteLine(arg);  // 輸出: 16
    }

    static void SquareVal(int valParameter) {
        valParameter *= valParameter;  // 修改副本
    }

    static void SquareRef(ref int refParameter) {
        refParameter *= refParameter;  // 修改原變數
    }
}

關鍵點總結

  • 值傳遞:建立副本,方法內操作不影響呼叫端變數。
  • 引用傳遞 (ref/out):傳遞變數地址,方法內修改直接反映到原變數。
  • out 要求方法在返回前必須賦值,ref 則要求呼叫前已初始化。

二、傳遞結構 vs 傳遞類實例的本質差異

這是許多開發者容易混淆的地方。核心在於值類型與引用類型的語意差異。

代碼示例

class TheClass { public string willIChange; }
struct TheStruct { public string willIChange; }

class TestClassAndStruct {
    static void ClassTaker(TheClass c) {
        c.willIChange = "Changed";
    }

    static void StructTaker(TheStruct s) {
        s.willIChange = "Changed";
    }

    static void Main() {
        TheClass testClass = new TheClass();
        TheStruct testStruct = new TheStruct();

        testClass.willIChange = "Not Changed";
        testStruct.willIChange = "Not Changed";

        ClassTaker(testClass);
        StructTaker(testStruct);

        Console.WriteLine("Class field = {0}", testClass.willIChange);  // Changed
        Console.WriteLine("Struct field = {0}", testStruct.willIChange);  // Not Changed
        Console.ReadKey();
    }
}

輸出結果

Class field = Changed
Struct field = Not Changed

深度解析

特性類 - 引用類型結構 - 值類型
記憶體分配 堆積,變數存儲引用(地址) 堆疊(通常),變數直接存儲資料
傳遞給方法時 複製「引用」(地址副本),雙方指向同一物件 複製「整個結構實體」,方法操作的是獨立副本
修改欄位/屬性 影響原物件 僅影響副本,原結構不變
重新指派參數變數 (c = new TheClass()) 僅改變區域引用指向,不影響呼叫端引用 不適用(結構不可為 null,通常不重新指派)

為什麼會這樣?

  • ClassTaker 參數 c 是 testClass 引用的副本,兩者指向同一堆積物件。修改 c.willIChange 實際修改該物件欄位,故 testClass 反映變化。
  • StructTaker 參數 s 是 testStruct 的完整副本。修改 s.willIChange 僅影響副本,方法結束副本銷毀,原 testStruct 保持不變。

三、實務建議

  1. 預設使用類:引用語意符合大多數業務物件直覺,避免大型結構複製開銷。
  2. 結構適用場景:小型、不可變、邏輯上屬於值的類型(如座標、日期、貨幣)。
  3. 需修改結構時:改用 ref 傳遞結構,或讓方法返回新結構實例。
  4. 避免「傳遞類引用卻期望不影響原物件」:若需隔離,請手動深層複製或採用不可變模式。

四、結語

掌握值/引用傳遞與值/引用類型的組合行為,是編寫正確、高效 C# 代碼的基石。牢記:類傳引用(地址副本),結構傳值(實體副本),即可避開 90% 的坑。

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