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

參數傳遞藝術(下):引用類型按值/按引用、ref/out 深度解析

     編輯:關於.NET

承接[上集](第十一回),本文聚焦引用類型參數傳遞的微妙差異、ref/out 本質比較、以及字串類型的特殊行為成因。

引用類型按值傳遞:傳的是「引用的副本」

class ArgsByRef { public int i = 10; }
static void AddRef(ArgsByRef abf) { abf.i = 20; }
static void Main() {
    var abf = new ArgsByRef();
    AddRef(abf);
    Console.WriteLine(abf.i); // 20 - 原物件被修改
}

本質:參數 abf 複製的是參考位址(指標值),雙方指向同一堆上物件,成員修改可見;但若在方法內 abf = new ArgsByRef(),外部變數不受影響(指向改變)。

引用類型按引用傳遞 (ref/out):傳的是「引用的位址」

傳遞方式傳遞內容效果
值類型按值實例副本不影響原值
引用類型按值引用副本 (指標值)可改物件內容,不可換物件
值類型 ref變數位址可改原值
引用類型 ref引用變數位址 (指標的指標)可換物件、可改內容
static void ChangeByRef(ref string s) { s = "New"; }
static void Main() {
    string str = "Old";
    ChangeByRef(ref str);
    Console.WriteLine(str); // New - 原變數指向新物件
}

字串的特殊性:不可變性造成的「假象」

static void ChangeStr(string s) { s = "Changed"; }
static void Main() {
    string str = "Original";
    ChangeStr(str);
    Console.WriteLine(str); // Original - 未改變
}

原因:string 是不可變 (immutable) 參考類型。s = "Changed" 在堆上建立新字串,s 指向新位址,外部 str 仍指向原字串。這是按值傳遞的正常行為,非特殊規則。若需修改外部變數,必須加 ref。

ref vs out:編譯期規則不同,IL 完全相同

  • 相同點:CLR 層面均為「傳址」,IL 代碼無差別。ref/out 不能構成多載(void M(ref int) vs void M(out int) 衝突)。
  • 不同點:
    • ref:呼叫前必須初始化(確定記憶體位置)。
    • out:呼叫前不可初始化,方法內必須賦值(確定輸出)。
int x = 10; M(ref x);   // OK
int y; M(out y);        // OK,但 M 內必須 y = ...
// M(ref y); // 錯誤:未初始化
// int z = 10; M(out z); // 錯誤:out 參數不應預先賦值

參數陣列 params:編譯器語法糖

void Sum(params int[] nums) { ... }
Sum(1, 2, 3); // 編譯器轉為 Sum(new int[]{1,2,3})

params 實質為 [ParamArrayAttribute],限制:必須為一維陣列、最後一個參數、僅能出現一次。

總結

參數傳遞的核心在於「傳什麼」:值類型傳實例/位址,引用類型傳引用/引用位址。ref/out 統一為「傳址」,差異僅在編譯期驗證規則。理解記憶體模型(堆疊 vs 堆)是破解所有傳遞迷思的鑰匙。

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