浅谈ref与out区别
今天又一次碰到了ref與out區(qū)別的問題,當(dāng)初總認(rèn)為自己學(xué)的還不錯(cuò),但每次遇到后都要糾結(jié)一番,這次再次學(xué)習(xí)和鞏固一下。
MSDN中的定義:
ref 關(guān)鍵字使參數(shù)按引用傳遞。其效果是,當(dāng)控制權(quán)傳遞回調(diào)用方法時(shí),在方法中對參數(shù)所做的任何更改都將反映在該變量中。若要使用 ref 參數(shù),則方法定義和調(diào)用方法都必須顯式使用 ref 關(guān)鍵字。
?out 關(guān)鍵字會(huì)導(dǎo)致參數(shù)通過引用來傳遞。這與 ref 關(guān)鍵字類似,不同之處在于 ref 要求變量必須在傳遞之前進(jìn)行初始化。若要使用 out 參數(shù),方法定義和調(diào)用方法都必須顯式使用 out 關(guān)鍵字。
首先,我們來看一個(gè)簡單的例子:
??????? static void TestRefAndOut()
??????? {
??????????? string s1 = "Good Luck!";
??????????? TestRef(ref s1);
??????????? Console.WriteLine(s1);//output: Hello World!
??????? }
??????? static void TestRef(ref string str)
??????? {
??????????? str = "Hello World!";
??????? }
在TestRefAndOut()中將字符串s1以ref關(guān)鍵字的方式傳到方法TestRef(ref string str)中,在這個(gè)方法中,我們改變了s1的引用變量str的值,最后,回到TestRefAndOut()方法后輸出s1的值,發(fā)現(xiàn)其值已被改變。
將上例中的ref換成out,代碼如下:
??????? static void TestRefAndOut()
??????? {
??????????? string s1 = "Good Luck!";
??????????? //TestRef(ref s1);
??????????? TestOut(out s1);
??????????? Console.WriteLine(s1);//output: Hello World!
??????? }
??????? static void TestOut(out string str)
??????? {
??????????? str = "Hello World!";
??????? }
同樣,在將ref換成out后,會(huì)發(fā)現(xiàn)最后的輸出仍然是相同的,那這兩個(gè)關(guān)鍵字的區(qū)別是什么呢?
進(jìn)一步測試:
ref:
??????? static void TestRefAndOut()
??????? {
??????????? string s1 = "Good Luck!";
??????????? TestRef(ref s1);
??????? }
??????? static void TestRef(ref string str)
??????? {
??????????? Console.WriteLine(str);//output: Good Lick!???????????
??????? }
?out
??????? static void TestRefAndOut()
??????? {
??????????? string s1 = "Good Luck!";
??????????? TestOut(out s1);
??????? }
??????? static void TestOut(out string str)
??????? {
??????????? Console.WriteLine(str);//compile does not pass
??????? }
ref的那段代碼順利編譯,輸出"Good Luck!",而out那段代碼卻無法通過編譯,提示“Use of unassigned out parameter 'str' ”,即使用了未分配地址的out參數(shù)str。怎么回事呢?
原來out參數(shù)在進(jìn)入方法的時(shí)候,C#會(huì)自動(dòng)清空它的一切引用和指向,所以在上面的out例子中,必需先要為str參數(shù)賦值。如以下程序。
??????? static void TestRefAndOut()
??????? {
??????????? string s1 = "Good Luck!";
??????????? TestOut(out s1);
??????? }
??????? static void TestOut(out string str)
??????? {
??????????? str = "Hello World!";
??????????? Console.WriteLine(str);//output: Hello World!
??????? }
Ok,得到第一個(gè)區(qū)別: out 參數(shù)在進(jìn)入方法(函數(shù))時(shí)后清空自己,使自己變成一個(gè)干凈的參數(shù),也因?yàn)檫@個(gè)原因必須在方法返回之前或再使用out參數(shù)前為 out 參數(shù)賦值(只有地址沒有值的參數(shù)是不能被.net接受的);而ref參數(shù)是不需要在被調(diào)用方法使用前先賦值的,甚至也可以被調(diào)用方法中不改變r(jià)ef參數(shù)的值,這都不會(huì)引起編譯錯(cuò)誤。
在繼續(xù)看一段代碼:
ref:
??????? static void TestRefAndOut()
??????? {
??????????? string s1;
??????????? TestRef(ref s1);
??????????? Console.WriteLine(s1);//compile does not pass!
??????? }
??????? static void TestRef(ref string str)
??????? {
??????????? str = Hello World!";
??????? }???
out:
??????? static void TestRefAndOut()
??????? {
??????????? string s1;
??????????? TestOut(out s1);
??????????? Console.WriteLine(s1);//output: Hello World!
??????? }
??????? static void TestOut(out string str)
??????? {
??????????? str = "Hello World!";
??????? }??
這回發(fā)現(xiàn),ref這段代碼無法編譯了,s1是一個(gè)空引用,所以無法使用。而out參數(shù)則因?yàn)樯鲜龅哪莻€(gè)原因,它不在乎s1是不是空引用,因?yàn)榫退鉺1不是空引用,它也會(huì)把s1變成空引用的。Ok,第二個(gè)區(qū)別:ref參數(shù)在使用前必需初始化,而out不需要。嗯,由上邊兩個(gè)區(qū)別可以引申一下,out參數(shù)只進(jìn)不出,ref參數(shù)有進(jìn)有出。在用法上概括一下就是:out適合用在需要retrun多個(gè)返回值的地方,而ref則用在需要被調(diào)用的方法修改調(diào)用者的引用的時(shí)候。
總結(jié)一下:
首先:兩者都是按地址傳遞的,使用后都將改變原來的數(shù)值。很多人在論壇上解釋說out是按數(shù)值傳遞,是錯(cuò)誤的。簡單的測試后可以知道out使用也能改變數(shù)值的,所以肯定是按照地址傳遞的。
其次:rel可以把參數(shù)的數(shù)值傳遞進(jìn)函數(shù),但是out是要把參數(shù)清空,就是說你無法把一個(gè)數(shù)值從out傳遞進(jìn)去的,out進(jìn)去后,參數(shù)的數(shù)值為空,所以你必須初始化一次。這個(gè)就是兩個(gè)的區(qū)別,或者說就像有的網(wǎng)友說的,rel是有進(jìn)有出,out是只出不進(jìn)。
所以也就不難得出以下這道題的答案了:
class TestApp
??? {
??????? static void outTest(out int x, ref int y)
??????? {
??????????? x = 1;
??????????? y = 2;
??????? }
??????? static void refTest(ref int x, out int y)
??????? {
??????????? x = 1;
??????????? y = x;
??????? }
??????? public static void Main()
??????? {
??????????? int a = 1;
??????????? int b = 3;
??????????? outTest(out a, ref b);
??????????? outTest(out a, ref b);
??????????? refTest(ref a, out b);
??????????? Console.WriteLine("a={0};b={1}", a, b);
??????????? Console.ReadKey();
??????? }
??? }
?
轉(zhuǎn)載于:https://www.cnblogs.com/skyer-2013/archive/2013/02/18/2916231.html
總結(jié)
以上是生活随笔為你收集整理的浅谈ref与out区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS Apps核心对象
- 下一篇: arm学习笔记五(c/c++与arm汇编