問(wèn)題:為什么c#中要有ref和out?(而java中沒(méi)有) 首先:兩者都是按地址傳遞的,使用后都將改變?cè)瓉?lái)參數(shù)的數(shù)值。 其次:ref可以把參數(shù)的數(shù)值傳遞進(jìn)函數(shù),但是out是要把參數(shù)清空,就是說(shuō)你無(wú)法把一個(gè)數(shù)值從out傳遞進(jìn)去的,out進(jìn)去后,參數(shù)的數(shù)值為空,所以你必須初始化一次。這個(gè)就是兩個(gè)的區(qū)別,或者說(shuō)就像有的網(wǎng)友說(shuō)的,ref是有進(jìn)有出,out是只出不進(jìn)。
現(xiàn)編碼如下: class Program 運(yùn)行結(jié)果: 交換前 a = 1 b = 2 方法內(nèi) a = 2 b = 1 交換后 a = 1 b = 2 斷言失敗,并未達(dá)到我們的需求! 原因分析:int類型為值類型,它存在于線程的堆棧中。當(dāng)調(diào)用Swap(a,b)方法時(shí),相當(dāng)于把a(bǔ),b的值(即1,2)拷貝一份,然后在方法內(nèi)交換這兩個(gè)值。交換完后,a還是原來(lái)的a,b還是原來(lái)的b。這就是C#中按值傳遞的原理,傳遞的是變量所對(duì)應(yīng)數(shù)據(jù)的一個(gè)拷貝,而非引用。 解決方案:因此,C#中提出了ref 和out兩個(gè)關(guān)鍵字。 修改代碼如下即可實(shí)現(xiàn)我們想要的結(jié)果: class Program 同理用out同樣可以實(shí)現(xiàn)我們的需求。 下面談?wù)剅ef和out到底有什么區(qū)別: 1關(guān)于重載 原則:有out|ref關(guān)鍵字的方法可以與無(wú)out和ref關(guān)鍵字的方法構(gòu)成重載;但如想在out和ref間重載,編譯器將提示:不能定義僅在ref和out的上的方法重載 ref 和 out 關(guān)鍵字在運(yùn)行時(shí)的處理方式不同,但在編譯時(shí)的處理方式相同。因此,如果一個(gè)方法采用 ref 參數(shù),而另一個(gè)方法采用 out 參數(shù),則無(wú)法重載這兩個(gè)方法。例如,從編譯的角度來(lái)看,以下代碼中的兩個(gè)方法是完全相同的,因此將不會(huì)編譯以下代碼: class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded // methods that differ only on ref and out". public void SampleMethod(out int i) { } public void SampleMethod(ref int i) { } }
但是,如果一個(gè)方法采用 ref 或 out 參數(shù),而另一個(gè)方法不采用這兩類參數(shù),則可以進(jìn)行重載,如下所示: class RefOutOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(out int i) { } } 2 關(guān)于調(diào)用前初始值 原則:ref作為參數(shù)的函數(shù)在調(diào)用前,實(shí)參必須賦初始值。否則編譯器將提示:使用了未賦值的局部變量; out作為參數(shù)的函數(shù)在調(diào)用前,實(shí)參可以不賦初始值。 3 關(guān)于在函數(shù)內(nèi),引入的參數(shù)初始值問(wèn)題 原則:在被調(diào)用函數(shù)內(nèi),out引入的參數(shù)在返回前至少賦值一次,否則編譯器將提示:使用了未賦值的out參數(shù); 在被調(diào)用函數(shù)內(nèi),ref引入的參數(shù)在返回前不必為其賦初值。 總結(jié):C#中的ref和out提供了值類型按引用進(jìn)行傳遞的解決方案,當(dāng)然引用類型也可以用ref和out修飾,但這樣已經(jīng)失去了意義。因?yàn)橐脭?shù)據(jù)類型本來(lái)就是傳遞的引用本身而非值的拷貝。ref和out關(guān)鍵字將告訴編譯器,現(xiàn)在傳遞的是參數(shù)的地址而不是參數(shù)本身,這和引用類型默認(rèn)的傳遞方式是一樣的。同時(shí),編譯器不允許out和ref之間構(gòu)成重載,又充分說(shuō)明out和ref的區(qū)別僅是編譯器角度的,他們生成的IL代碼是一樣的。有人或許疑問(wèn),和我剛開始學(xué)習(xí)的時(shí)候一樣的疑惑:值類型在托管堆中不會(huì)分配內(nèi)存,為什么可以按地址進(jìn)行傳遞呢?值類型雖然活在線程的堆棧中,它本身代表的就是數(shù)據(jù)本身(而區(qū)別于引用數(shù)據(jù)類型本身不代表數(shù)據(jù)而是指向一個(gè)內(nèi)存引用),但是值類型也有它自己的地址,即指針,現(xiàn)在用ref和out修飾后,傳遞的就是這個(gè)指針,所以可以實(shí)現(xiàn)修改后a,b的值真正的交換。這就是ref和out給我們帶來(lái)的好處。 |
|