關於C#方法中引用類型參數傳遞

来源:https://www.cnblogs.com/memoyu/archive/2023/02/17/17131079.html
-Advertisement-
Play Games

本文敘述的問題的根源在於對C#基礎知識掌握不牢固,從而在遇到難以理解的問題時浪費了大量時間; 在此也警示自己,該啃啃基礎書籍了! 話不多說,先上代碼: 先看問題 services.AddEasyCaching(option => { option.UseHybrid(config => { .... ...


本文敘述的問題的根源在於對C#基礎知識掌握不牢固,從而在遇到難以理解的問題時浪費了大量時間;
在此也警示自己,該啃啃基礎書籍了!
話不多說,先上代碼:

先看問題

services.AddEasyCaching(option =>
{
    option.UseHybrid(config =>
    {
        .....
    })
    .WithZookeeeperBus(busConf =>
    {
        // 方式1
        busConf.ConnectionString = "192.168.3.86:2181";
        // 方式2
        busConf = new ZkBusOptions
        {
            ConnectionString = "192.168.3.86:2181",
        };
    });
});

這是我在使用EasyCaching時的一段註冊代碼,在配置Zookeeeper Bus時調用了WithZookeeeperBus(Action<ZkBusOptions>)拓展方法,並採用瞭如上兩種賦值方式,看似都能正常配置,但實際不盡人意:
方式1:配置正常;
方式2:配置無效,最終ConnectionString=null

what?肯定是編譯器問題!( 確信
此時我的心情極其複雜,這兩種賦值不是一樣的?

問題在哪?

一開始,我甚至懷疑是自己對Action<T>的理解不到位,存在某種機制導致的問題,但事實證明,飯可以亂吃,鍋不能亂甩;
每每想起這,不由得老臉一紅!

問題在這

實則問題是在最基礎的方法傳參問題;
咱們可以先理解一下方法傳參存在哪幾種情況,以及情況對應傳參方式;
在C#參數傳遞分為如下四種:

  • 值類型的值傳遞(將值類型的副本傳遞給方法)
  • 值類型的引用傳遞(將值類型本身傳遞給方法,例如:使用了ref int a
  • 引用類型的值傳遞(將引用的副本傳遞給方法 )
  • 引用類型的引用傳遞(將引用本身傳遞給方法,例如:使用了ref object o

此時,如果你已經悟了,那文章到此結束,還一知半解的,請繼續往下看;

再細一點

先看看如下代碼:

void Main()
{
	var p = new Person { Name = "jason", Age = 19 };
    // 賦值方法 1
	AssignmentPerson_1(p);
    Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");

    // 賦值方法 2
    AssignmentPerson_2(p);
	Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");
}

public void AssignmentPerson_1(Person t)
{
	var np = new Person { Name = "jack", Age = 18 };
	t = np;
}

public void AssignmentPerson_2(Person t)
{
	var np zhanzhi

很顯然,在本文起始的教訓下,答案是明顯,會輸出如下:
Name = "jason"; Age = 19
Name = "jack"; Age = 18

首先,在main中創建了p,假設p在棧中的地址為0x0001,棧值為指向堆中實例的地址0x00D1

賦值方法-1

然後,開始調用AssignmentPerson_1(Person t),並傳入p
此時,不是直接將 p(棧地址:0x0001)傳入方法,而是拷貝了一份p(棧地址:0x0005),並且同時將棧值賦為0x00D1,傳入方法中;
所以,AssignmentPerson_1(Person t)t的地址為0x0005

最後,新建np,棧地址為0x000A,棧值為指向堆中實例的地址0x00D5
並將t = npt的棧值被替換了0x00D1 -> 0x00D5

最終,p的棧值還是0x00D1,並且0x00D1中的堆值也並未發生變化,所以賦值無效;

賦值方法-2

同理,當調用AssignmentPerson_2(Person t)時,同樣傳入p,同樣新建np
但是,並沒有替換t的棧值,它仍舊與p指向的堆地址相同,為0x00D1;
此時賦值操作只是替換了堆值中實例的屬性值:t.Name = np.Namet.Age = np.Age

所以,t指向的堆值發生了變化, tp又指向地址相同,p的實例屬性值也就發生了變化;

總結

該讀一本《CLR via》了!

參考

1-關於C#函數對象參數傳遞的問題
2-徹底澄清:C#方法參數


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.讓伺服器監聽客戶端的連接請求 1.1 代碼塊 #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include<stdio.h> #include<stdlib.h> #define BUFFER_LEN 1 ...
  • 關於靜態代碼塊和匿名代碼塊以及結構體在程式運行過程中的調用順序實驗 ​ 今天學習JAVA看到了static修飾符部分,講到了有關匿名代碼和靜態代碼部分。此時又突然想到前面所學關於new是調用類的結構體知識,同時結合繼承關係,想看看在這些條件下匿名代碼塊、靜態代碼塊以及類構造體的調用順序。 ​ 編寫了 ...
  • 教程簡介 Google Plus初學者教程 - 從基本到高級概念的簡單簡單步驟學習Google Plus,其中包括簡介,業務頁面設置,創建新帳戶,瀏覽Google Plus,添加業務詳細信息,上傳個人資料圖片,添加封面圖片,圈子,社區,環聊,活動,上傳帖子,編輯帖子,刪除帖子,轉發帖子,報告帖子,促 ...
  • 一、背景 開發一款Idea插件,實現對yaml文件的定製化格式檢查。 !! 後指定的類路徑是否準確 yaml中的key是否equal類中field的name value是否能夠轉換成類中field的類型 …… 完成代碼功能上線後,使用過程發現很多問題。後在主管幫助下,對代碼進行了重構。事後對重構前後 ...
  • 教程簡介 Microsoft Expression Web Tutorial for Beginners - 從基本到高級概念的簡單簡單步驟學習Microsoft Expression Web,其中包括概述,環境設置,新網站,空白網頁,網頁佈局,HTML佈局,水平導航,垂直導航,驗證頁面,動態Web ...
  • 什麼是素數? 質數又稱素數。一個大於1的自然數,除了1和它自身外,不能被其他自然數整除的數叫做質數;否則稱為合數(規定1既不是質數也不是合數)。 實際案例 比如我們想找出1-1000的所有素數 思路1 可以先定義一個方法 primeNumber//參數列表用來接收所想找的素數範圍 public st ...
  • 本文介紹基於Python的隨機森林(Random Forest,RF)回歸代碼,以及模型超參數(包括決策樹個數與最大深度、最小分離樣本數、最小葉子節點樣本數、最大分離特征數等)自動優化的代碼~ ...
  • nano /etc/motd // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/` '\____ // // .' \\| |// `. // // / \\||| : |||// ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...