日韩欧美国产精品免费一二-日韩欧美国产精品亚洲二区-日韩欧美国产精品专区-日韩欧美国产另-日韩欧美国产免费看-日韩欧美国产免费看清风阁

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#.net core 基礎(chǔ) - 值傳遞、引用傳遞

freeflydom
2025年1月2日 8:39 本文熱度 2242

不知道你在開發(fā)過程中有沒有遇到過這樣的困惑:這個(gè)變量怎么值被改?這個(gè)值怎么沒變?

今天就來和大家分享可能導(dǎo)致這個(gè)問題的根本原因值傳遞 vs 引用傳遞。

在此之前我們先回顧兩組基本概念:

值類型 vs 引用類型

值類型: 直接存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)在棧上;

引用類型: 存儲(chǔ)數(shù)據(jù)對(duì)象的引用,數(shù)據(jù)實(shí)際存儲(chǔ)在堆上。

形參 vs 實(shí)參

形參: 即形式參數(shù),表示調(diào)用方法時(shí),方法需要你傳遞的值。方法聲明定義了其形參。也就是說在定義方法時(shí),緊跟在方法名后面括號(hào)中的參數(shù)列表就是形參。

實(shí)參: 即實(shí)際參數(shù),表示調(diào)用方法時(shí),你傳遞給方法形參的值。調(diào)用代碼在調(diào)用過程時(shí)提供實(shí)參。也就是說在調(diào)用方法時(shí),緊跟在方法名后面括號(hào)中的參數(shù)列表就是實(shí)參。

再來回顧一下值類型和引用類型在內(nèi)存中是怎么存儲(chǔ)的呢?

對(duì)于值類型變量的值直接存儲(chǔ)在棧中,如下圖的int a=10,10就直接存在棧空間中,而其棧空間對(duì)應(yīng)的內(nèi)存地址為0x66666668;對(duì)于引用類型變量本身存儲(chǔ)的是實(shí)例對(duì)象的引用,即實(shí)例對(duì)象在堆中的實(shí)際內(nèi)存地址,因此引用類型變量是存儲(chǔ)其實(shí)例對(duì)象的引用于棧上,如下圖中變量Test a在棧中實(shí)際存儲(chǔ)的是實(shí)例對(duì)象Test a在堆中的內(nèi)存地址0x88888880,而棧空間對(duì)應(yīng)的內(nèi)存地址為0x66666668。

棧也是有內(nèi)存地址的,這一點(diǎn)很重要,無論棧空間上存儲(chǔ)的是值還是引用地址,這個(gè)棧空間本身也有自己對(duì)應(yīng)的內(nèi)存地址。

什么是值傳遞?什么是引用傳遞?

值傳遞:如果變量按值傳遞給方法,則會(huì)把變量的副本傳遞給方法。對(duì)于值類型則把變量的副本傳遞給方法,對(duì)于引用類型則把變量的引用的副本傳遞給方法。因此被調(diào)用方法參數(shù)會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,因此在方法內(nèi)部對(duì)變量修改并不會(huì)影響原來的值。

引用傳遞:如果變量按引用傳遞給方法,則會(huì)把變量的引用傳遞給方法,對(duì)于值類型則把變量的棧空間地址傳遞給方法,對(duì)于引用類型則把變量的引用的棧空間地址傳遞給方法。因此被調(diào)用方法參數(shù)不會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,意味著形參與實(shí)參共同指向相同的內(nèi)存地址,因此在方法內(nèi)部修對(duì)變量修改會(huì)影響原來的值。

上面的描述可能有點(diǎn)拗口,下面我們?cè)诨谥殿愋汀⒁妙愋汀⒅祩鬟f、引用傳遞各種組合進(jìn)行一個(gè)詳細(xì)說明。

01、值類型按值傳遞

當(dāng)值類型按值傳遞時(shí),調(diào)用者會(huì)把值類型變量的副本傳遞給方法,因此被調(diào)用方法參數(shù)會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,因此當(dāng)在方法內(nèi)部對(duì)參數(shù)進(jìn)行修改時(shí)并不會(huì)影響調(diào)用者調(diào)用處的值類型變量。

傳遞值類型變量的副本就是相當(dāng)于在棧上,又復(fù)制了一個(gè)同樣的值,而且內(nèi)存地址還不一樣,所以互不影響。如下圖把a(bǔ)賦值給b,則b直接新開辟了一個(gè)棧空間,雖然a和b都是10,但是它們?cè)诓煌牡刂房臻g中,因此如果他們各自被修改了,也互不影響。

下面我們寫個(gè)例子演示一下,這個(gè)例子就是定義個(gè)變量a并賦值,然后調(diào)用一個(gè)方法此方法內(nèi)對(duì)傳進(jìn)來的參數(shù)a進(jìn)行加1,具體代碼如下:

public static void ValueByValueRun(){
    var a = 10;
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a 值:{a}");
    ChangeValueByValue(a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a 值:{a}");
}public static void ChangeValueByValue(int a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a 值:{a}");
    a = a + 1;
    Console.WriteLine($"    被調(diào)用方法-修改后 a 值:{a}");
}

運(yùn)行結(jié)果如下:

通過代碼執(zhí)行結(jié)果可以發(fā)現(xiàn),方法內(nèi)對(duì)變量的修改已經(jīng)生效,但是不沒有影響到調(diào)用者調(diào)用處的變量值。

02、引用類型按值傳遞

當(dāng)引用類型按值傳遞時(shí),調(diào)用者會(huì)把引用類型變量的引用副本傳遞給方法,因此被調(diào)用方法參數(shù)會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,而對(duì)于一個(gè)引用類型變量來說其本身存儲(chǔ)的就是引用類型實(shí)例對(duì)象的引用副本,而方法接收到的也是此變量引用的副本,所以調(diào)用者參數(shù)和被調(diào)用方法參數(shù)是引用了同一個(gè)實(shí)例對(duì)象的兩個(gè)引用副本。如下圖Test a可以理解為調(diào)用者傳的實(shí)參,Test b可以理解為被調(diào)用方法定義的形參,這兩個(gè)參數(shù)都只是指向堆中Test a的引用副本。

因此可以得出兩個(gè)結(jié)論:

1、變量a和b都是指向?qū)嵗龑?duì)象Test a的引用,所以無論變量a或b,只要有一個(gè)更新了實(shí)例成員則另一個(gè)變量也會(huì)同步發(fā)生變化。

2、雖然變量a和b都是指向?qū)嵗龑?duì)象Test a的引用,但是他們存儲(chǔ)在棧上的內(nèi)存地址卻不同,因此如果他們各種重新分配實(shí)例也就是new一個(gè)新對(duì)象,則另一個(gè)變量無法感知到還是保持原因狀態(tài)不變。

我們先用代碼說明第一個(gè)結(jié)論:

public static void ChangeReferenceByValueRun(){
    var a = new Test
    {
        Age = 10
    };
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a.Age 值:{a.Age}");
    ChangeReferenceByValue(a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a.Age 值:{a.Age}");
}
public static void ChangeReferenceByValue(Test a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a.Age 值:{a.Age}");
    a.Age = a.Age + 1;
    Console.WriteLine($"    被調(diào)用方法-修改后 a.Age 值:{a.Age}");
}

運(yùn)行結(jié)果如下:

可以看到被調(diào)用方法中a實(shí)例對(duì)象的Age屬性發(fā)生變化后,調(diào)用者中變量也同步發(fā)生了變化。

對(duì)于第二個(gè)結(jié)論我們這樣論證,在方法中直接對(duì)參數(shù)new一個(gè)新對(duì)象,看看原變量是否發(fā)生變化,代碼如下:

public static void NewReferenceByValueRun(){
    var a = new Test
    {
        Age = 10
    };
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a.Age 值:{a.Age}");
    NewReferenceByValue(a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a.Age 值:{a.Age}");
}
public static void NewReferenceByValue(Test a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a.Age 值:{a.Age}");
    a = new Test
    {
        Age = 100
    };
    Console.WriteLine($"    被調(diào)用方法-new后 a.Age 值:{a.Age}");
}

執(zhí)行結(jié)果如下:

可以發(fā)現(xiàn)當(dāng)在方法中對(duì)變量執(zhí)行new操作后,調(diào)用者處的變量并沒有發(fā)生變化。

為什么會(huì)這樣呢?因?yàn)閷?duì)于引用類型來說,形參和實(shí)參是對(duì)引用類型的實(shí)例對(duì)象引用的兩個(gè)副本,而這兩個(gè)副本存儲(chǔ)在棧上又分別在不同的內(nèi)存地址空間上,而new主要就是重新分配內(nèi)存,這就導(dǎo)致形參變量a=new后,棧上形參變量a指向了Test新的實(shí)例對(duì)象的引用,而實(shí)參變量a還是保持原有實(shí)例對(duì)象引用不變。

如下圖所示。

03、值類型按引用傳遞

當(dāng)值類型按引用傳遞時(shí),調(diào)用者會(huì)把值類型變量對(duì)應(yīng)的棧空間地址傳遞給方法,因此被調(diào)用方法參數(shù)不會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,因此當(dāng)在方法內(nèi)部對(duì)參數(shù)進(jìn)行修改時(shí)并同樣會(huì)影響調(diào)用者調(diào)用處的值類型變量。

傳遞值類型變量對(duì)應(yīng)的棧空間地址就意味著形參與實(shí)參共同指向相同的內(nèi)存地址,所以才導(dǎo)致對(duì)形參修改時(shí),實(shí)參也會(huì)同步發(fā)生變化。

我們用一個(gè)小例子演示一下:

public static void ValueByReferenceRun(){
    Console.WriteLine($"值類型按引用傳遞");
    var a = 10;
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a 值:{a}");
    ChangeValueByReference(ref a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a 值:{a}");
}
public static void ChangeValueByReference(ref int a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a 值:{a}");
    a = a + 1;
    Console.WriteLine($"    被調(diào)用方法-修改后 a 值:{a}");
}

執(zhí)行結(jié)果如下:

可以發(fā)現(xiàn)調(diào)用者處的值類型變量已經(jīng)發(fā)生改變。

04、引用類型按引用傳遞

當(dāng)引用類型按引用傳遞時(shí),調(diào)用者會(huì)把引用類型變量對(duì)應(yīng)的棧空間地址傳遞給方法,因此被調(diào)用方法參數(shù)不會(huì)創(chuàng)建一個(gè)新的內(nèi)存地址用于接收存儲(chǔ)變量,因此當(dāng)在方法內(nèi)部對(duì)參數(shù)進(jìn)行修改時(shí)并同樣會(huì)影響調(diào)用者調(diào)用處的引用類型變量。

傳遞引用類型變量對(duì)應(yīng)的棧空間地址就意味著形參與實(shí)參共同指向相同的內(nèi)存地址,因此對(duì)形參修改時(shí),實(shí)參也會(huì)同步發(fā)生變化,而且這個(gè)里的修改不單單指修改實(shí)例成員,還包括new一個(gè)新實(shí)例對(duì)象。

下面我們看一個(gè)修改實(shí)例成員的例子:

public static void ChangeReferenceByReferenceRun(){
    Console.WriteLine($"引用類型按引用傳遞 - 修改實(shí)例成員");
    var a = new Test
    {
        Age = 10
    };
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a.Age 值:{a.Age}");
    ChangeReferenceByReference(ref a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a.Age 值:{a.Age}");
}
public static void ChangeReferenceByReference(ref Test a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a.Age 值:{a.Age}");
    a.Age = a.Age + 1;
    Console.WriteLine($"    被調(diào)用方法-修改后 a.Age 值:{a.Age}");
}

執(zhí)行結(jié)果如下:

再看看new一個(gè)新對(duì)象的例子:

public static void NewReferenceByReferenceRun(){
    Console.WriteLine($"引用類型按引用傳遞 - new 新實(shí)例");
    var a = new Test
    {
        Age = 10
    };
    Console.WriteLine($"調(diào)用者-調(diào)用方法前 a.Age 值:{a.Age}");
    NewReferenceByReference(ref a);
    Console.WriteLine($"調(diào)用者-調(diào)用方法后 a.Age 值:{a.Age}");
}
public static void NewReferenceByReference(ref Test a){
    Console.WriteLine($"    被調(diào)用方法-接收到 a.Age 值:{a.Age}");
    a = new Test
    {
        Age = 100
    };
    Console.WriteLine($"    被調(diào)用方法-new后 a.Age 值:{a.Age}");
}

執(zhí)行結(jié)果如下:

另外string是一個(gè)特殊的引用類型,string類型變量的按值傳遞和按引用傳遞和值類型是一致的,也就是要把string類型當(dāng)值類型一樣看待就行。string類型的特殊性我們后面會(huì)單獨(dú)具體介紹。

在C#中以下修飾符可應(yīng)用與參數(shù)聲明,并且會(huì)使得參數(shù)按引用傳遞:ref、out、readonly ref、in。對(duì)于每個(gè)修飾符具體怎么使用就不再這里細(xì)說了。

相信到這里你應(yīng)該就可以回答我之前在《LeetCode題集-2 - 兩數(shù)相加》最后提的問題了。

:測(cè)試方法代碼以及示例源碼都已經(jīng)上傳至代碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Planner

轉(zhuǎn)自https://www.cnblogs.com/hugogoos/p/18419656


該文章在 2025/1/2 8:42:30 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 国产精品自产在线观看免费 | 三级三级三级a级全黄 | 在线视频一区二区 | 视频在线一区二区三区 | 乱码一二 | 亚洲欧美精品精品aⅴ | 娇妻羞涩交换 | 伊人焦久综合影院每日更新 | 天美传媒在线观看果 | 日本中文字幕在线视频一区 | 中文区永久区乱码六区 | 在线观看中文字幕2025 | 亚洲一区二区又黄又爽在线观看 | 国产精品视频高清在线播放 | 最好看的中文字幕高清电影 | 91九色精品国产自产精品 | 国产精品自在欧美一区 | 日日摸处处碰夜夜爽 | 秋霞影院 | 色与欲影视天天影视 | 精品+在线+国产手机 | 免费三级网站 | 国产福利日本一区二区三区 | 国产精品三级不卡电影 | 亚洲中文字幕精品有码在线 | 把你的香肠放入我的扇贝里 | 国产人成视频 | 欧美亚洲国产经典 | 他扒开我小泬添我视频 | 99热门精品一区二区三区无 | 日本一区二区三区免费乱视频 | 在线午夜福利频在线播放 | 日本免费不卡高清网站视频 | 欧美高清国产一区二区三区 | 亚洲va在线va天堂va在线 | 日韩v午夜视频在线观看 | 一区二区三区不卡 | 亚洲午夜视频在线观看 | 日本免费一级婬片a级中文字幕 | 国产人妖专区视频在线一区 | 麻花影视最 |