對于一些初學(xué)者(包括工作幾年的人在內(nèi))來說,有時候?qū)τ诜椒ㄖg的參數(shù)傳遞的問題感覺比較困惑的,因?yàn)橹霸诿嬖嚨倪^程也經(jīng)常遇到參數(shù)傳遞的基礎(chǔ)面試題,這樣的面試題主要考察的開發(fā)人員基礎(chǔ)是否扎實(shí),對于C#中值類型和引用類型有沒有深入的一個理解——這個說的理解并不是簡單的對它們簡單一個定義描述,而在于它們在內(nèi)存中分布。所以本文章將帶領(lǐng)大家深入剖析下C#中參數(shù)傳遞的問題,并分享我自己的一個理解,只有你深入理解了才能在不運(yùn)行程序的情況就可以分析出參數(shù)傳遞的結(jié)果的。
商州ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
對于C#中的參數(shù)傳遞,根據(jù)參數(shù)的類型可以分為四類:
值類型參數(shù)的按值傳遞
引用類型參數(shù)的按值傳遞
值類型參數(shù)的按引用傳遞
引用類型參數(shù)的按引用傳遞
然而在默認(rèn)情況下,CLR方法中參數(shù)的傳遞都是按值傳遞的。為了幫助大家全面理解參數(shù)的傳遞,下面就這四種情況一一進(jìn)行分析。
對于參數(shù)又分為:形參和實(shí)參,形參指的是被調(diào)用方法中的參數(shù),實(shí)參指的是調(diào)用方法的參數(shù),下面結(jié)合代碼幫助大家理解形參和實(shí)參的概念:
class Program { static void Main(string[] args) { int addNum = 1; // addNum 就是實(shí)參, Add(addNum); } // addnum就是形參,也就是被調(diào)用方法中的參數(shù) private static void Add(int addnum) { addnum = addnum + 1; Console.WriteLine(addnum); } }
對于值類型的按值傳遞,傳遞的是該值類型實(shí)例的一個拷貝,也就是形參此時接受到的是實(shí)參的一個副本,被調(diào)用方法操作是實(shí)參的一個拷貝,所以此時并不影響原來調(diào)用方法中的參數(shù)值,為了證明這點(diǎn),看看下面的代碼和運(yùn)行結(jié)果就明白了:
class Program { static void Main(string[] args) { // 1. 值類型按值傳遞情況 Console.WriteLine("按值傳遞的情況"); int addNum = 1; Add(addNum); Console.WriteLine(addNum); Console.Read(); } // 1. 值類型按值傳遞情況 private static void Add(int addnum) { addnum = addnum + 1; Console.WriteLine(addnum); }
運(yùn)行結(jié)果為:
從結(jié)果中可以看出addNum調(diào)用方法之后它的值并沒有改變,Add 方法的調(diào)用只是改變了addNum的副本addnum的值,所以addnum的值修改為2了。然而我們的分析到這里并沒有結(jié)束,為了讓大家深入理解傳遞傳遞,我們有必要知道為什么值類型參數(shù)的按值傳遞不會修改實(shí)參的值,相信下面這張圖可以解釋你所有的疑惑:
當(dāng)傳遞的參數(shù)是引用類型的時候,傳遞和操作的是指向?qū)ο蟮囊茫吹竭@里,有些朋友會覺得此時不是傳遞引用嗎?怎么還是按值傳遞了?對于這個疑惑,此時確實(shí)是按值傳遞,此時傳遞的對象的地址,傳遞地址本身也是傳遞這個地址的值,所以此時仍然是按值傳遞的),此時方法的操作就會改變原來的對象。對于這點(diǎn)可能看文字描述會比較難理解下面結(jié)合代碼和分析圖來幫助大家理解下:
class Program { static void Main(string[] args) { // 2. 引用類型按值傳遞情況 RefClass refClass = new RefClass(); AddRef(refClass); Console.WriteLine(refClass.addnum); } // 2. 引用類型按值傳遞情況 private static void AddRef(RefClass addnumRef) { addnumRef.addnum += 1; Console.WriteLine(addnumRef.addnum); } } class RefClass { public int addnum=1; }
運(yùn)行結(jié)果為:
為什么此時傳遞引用就會修改原來實(shí)參中的值呢?對于這點(diǎn)我們還是參數(shù)在內(nèi)存中分布圖來解釋下:
對于String類型同樣是引用類型,然而對于string類型的按值傳遞時,此時引用類型的按值傳遞卻不會修改實(shí)參的值,可能很多朋友對于這點(diǎn)很困惑,下面具體看看下面的代碼:
class Program { static void Main(string[] args) { // 3. String引用類型的按值傳遞的特殊情況 string str = "old string"; ChangeStr(str); Console.WriteLine(str); } // 3. String引用類型的按值傳遞的特殊情況 private static void ChangeStr(string oldStr) { oldStr = "New string"; Console.WriteLine(oldStr); } }
運(yùn)行結(jié)果為:
對于為什么原來的值沒有被改變主要是因?yàn)閟tring的“不變性”,所以在被調(diào)用方法中執(zhí)行 oldStr="New string"代碼時,此時并不會直接修改oldStr中的"old string"值為"New string",因?yàn)閟tring類型是不變的,不可修改的,此時內(nèi)存會重新分配一塊內(nèi)存,然后把這塊內(nèi)存中的值修改為 “New string”,然后把內(nèi)存中地址賦值給oldStr變量,所以此時str仍然指向 "old string"字符,而oldStr卻改變了指向,它最后指向了 "New string"字符串。所以運(yùn)行結(jié)果才會像上面這樣,下面內(nèi)存分布圖可以幫助你更形象地理解文字表述:
不管是值類型還是引用類型,我們都可以使用ref 或out關(guān)鍵字來實(shí)現(xiàn)參數(shù)的按引用傳遞,然而按引用進(jìn)行傳遞的時候,需要注意下面兩點(diǎn):
方法的定義和方法調(diào)用都必須同時顯式使用ref或out,否則會出現(xiàn)編譯錯誤
CLR允許通過out 或ref參數(shù)來實(shí)現(xiàn)方法重載。如:
#region CLR 允許out或ref參數(shù)來實(shí)現(xiàn)方法重載 private static void Add(string str) { Console.WriteLine(str); } // 編譯器會認(rèn)為下面的方法是另一個方法,從而實(shí)現(xiàn)方法重載 private static void Add(ref string str) { Console.WriteLine(str); } #endregion
按引用傳遞可以解決由于值傳遞時改變引用副本而不影響引用本身的問題,此時傳遞的是引用的引用(也就是地址的地址),而不是引用的拷貝(副本)。下面就具體看看按引用傳遞的代碼:
class Program { static void Main(string[] args) { #region 按引用傳遞 Console.WriteLine("按引用傳遞的情況"); int num = 1; string refStr = "Old string"; ChangeByValue(ref num); Console.WriteLine(num); changeByRef(ref refStr); Console.WriteLine(refStr); #endregion Console.Read(); } #region 按引用傳遞 // 1. 值類型的按引用傳遞情況 private static void ChangeByValue(ref int numValue) { numValue = 10; Console.WriteLine(numValue); } // 2. 引用類型的按引用傳遞情況 private static void changeByRef(ref string numRef) { numRef = "new string"; Console.WriteLine(numRef); } #endregion }
運(yùn)行結(jié)果為:
從運(yùn)行結(jié)果可以看出,此時引用本身的值也被改變了,通過下面一張圖來幫忙大家理解下按引用傳遞的方式:
到這里參數(shù)的傳遞所有內(nèi)容就介紹完了??傊?strong>對于按值傳遞,不管是值類型還是引用類型的按值傳遞,都是傳遞實(shí)參的一個拷貝,只是值類型時,此時傳遞的是實(shí)參實(shí)例的一個拷貝(也就是值類型值的一個拷貝),而引用類型時,此時傳遞的實(shí)參引用的副本。對于按引用傳遞,傳遞的都是參數(shù)地址,也就是實(shí)例的指針。