C#的方法呼叫和引數傳遞你真的會嗎?讓我們一起來看看吧

首先,我不想上來就描述一大堆理論性的東西,說多了反而不一定清晰明瞭。讓我們直接看個程式碼示例吧!如下所示,Main方法中分別呼叫了四個測試方法,大家思考下,輸出的四個字元分別是什麼呢?

程式碼示例

using System;using System。Text;namespace MethodCall{ class Program { static void Main(string[] args) { StringBuilder sb = new StringBuilder(); //呼叫方法1 RestSb(sb); TestMethod1(sb); Console。WriteLine($“方法1的結果為:{sb}”); RestSb(sb); TestMethod2(ref sb); Console。WriteLine($“方法2的結果為:{sb}”); RestSb(sb); TestMethod3(sb); Console。WriteLine($“方法3的結果為:{sb}”); RestSb(sb); TestMethod4(ref sb); Console。WriteLine($“方法4的結果為:{sb}”); Console。ReadKey(); } static void TestMethod1(StringBuilder sb) { sb。Append(“小豆”); } static void TestMethod2(ref StringBuilder sb) { sb。Append(“小豆”); } static void TestMethod3(StringBuilder sb) { sb = new StringBuilder(“小豆”); } static void TestMethod4(ref StringBuilder sb) { sb = new StringBuilder(“小豆”); } ///

/// 重置StringBuilder的初始狀態為“洋” /// /// static void RestSb(StringBuilder sb) { if (sb == null) return; sb。Clear(); sb。Append(“洋”); } }}

呼叫結果

下面我們先來揭曉答案,然後再解釋下為什麼輸出的答案是這樣的。我們在VS中除錯的結果如下圖所示:

C#的方法呼叫和引數傳遞你真的會嗎?讓我們一起來看看吧

四個方法的呼叫結果

結果解釋

在解釋結果前,我們先要理解方法呼叫傳參的本質。方法呼叫時引數預設是傳值的,也就是說值會複製到目標引數(被呼叫的方法)中。對於值型別來說,這裡的值就是數值本身; 而對於應引用型別的變數,這裡的值其實就是對資料實際儲存位置的

引用

,也就是說複製其實是

複製的引用(地址)本身

。這樣在被呼叫的方法中是改不了引用本身的,但可以修改引用所指向的堆上的資料。

ref關鍵字:上面說了方法呼叫傳引數預設是以傳值的方式傳遞的,那麼引數前面加上ref之後,引數就會以

引用方式傳遞

。怎麼理解這句話呢?實際上,ref引數只是傳遞的

變數的別名

,作用只是為現有變數分配引數名,而非建立新變數並將實參的值複製給它。

有了上面兩點的理解,相信大家對輸出結果也有了很好的理解。

方法一解釋:方法一中的引數sb僅僅是main方法中sb引用值的複製,他們都指向堆的同一區域,所以新增字元“小豆”後,整個返回結果為“洋小豆”。

方法二解釋:方法二中的引數sb加上了ref關鍵字,說明這裡的sb和main方法中一樣,僅僅是個別名,所以最後的返回結果也是“洋小豆”。

方法三解釋:方法三中的引數sb也僅僅是main方法中sb引用值的複製,但是方法中又將這個引用複製指向了另一塊新建區域(new StringBuilder(“小豆”));但這

並不影響main方法中sb的指向

,所以最後返回結果為“洋”。

方法四解釋:方法四中的sb是main方法中sb的別名,所以在方法四中改變了別名的指向其實就是改變main方法中sb的指向,所以輸出結果為新的指向區域的值:“小豆”。

擴充套件思考

學了上面的知識點後,請大家思考問題:”引用型別的資料作為方法引數時,什麼時候需要加ref關鍵字什麼時候又不需要呢?“

感謝各位的閱讀,歡迎大家在評論區留言討論。如有不正確的地方,也歡迎大家指正!