C#中ref和out關鍵字的應用以及區別。
之前要學習一下C#的更深入的東西時,看到了ref和out的概念。看了一些教程之後,感覺還是明白了用法,但是不知道語言的深層含義。所以整理了一番,寫成博客,幫助大家可以理解,並且於我,也是一個重新整理思路的過程。
首先國際慣例,要了解一個東西的時候,首先明白它是什麼,然後明白它能做什麼,最後要知道爲什麼。
ref
ref的定義
ref:MSDN的定義爲:“The ref keyword indicates a value that is passed by reference.”就是通過引用來傳遞參數。ref也是Reference的縮寫。瞭解了定義之後,ref怎麼用呢?首先我們要明白值類型和引用類型的概念。這裏的ref基本上就是服務於值類型的。
ref 的使用
//不使用 ref;
void Method(int myRefInt)
{
myRefInt += 66;
}
int number = 1;
Method(number);
Console.WriteLine(number);
**//輸出 : 1;**
//使用ref
void Method(ref int myRefInt)
{
myRefInt += 66;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
**//輸出:67**
看到這裏想必已經明白了:
- 不使用ref的時候,函數收到的值是1,然後在
Method(int myRefInt)
方法中,局部變量myRefInt
做了累加之後,在方法執行完成之後就已經銷燬了。number
的值還是1。 - 使用ref的時候,函數
Method(ref int myRefInt)
值收到的是number
的地址,函數中執行的myRefInt+=66;
此時相當於number+=66;
直接修改了number
地址的值。
那就可以等處結論了:ref是通過給方法傳遞值類型的參數,直接操作同一個變量的關鍵字。
out
out的定義:來自MSDN
- As a parameter modifier, which lets you pass an argument to a method by reference rather than by value./“out”作爲一個參數修飾符,允許您通過引用而不是通過值將參數傳遞給方法。
- In generic type parameter declarations for interfaces and delegates, which specifies that a type parameter is covariant./在接口和委託的泛型類型參數聲明中,它指定類型參數是協變的。
今天的語境下,我們只討論第一種作爲引用傳遞參數的定義。
out的用法
int number;
Method(number);
void Method(int myRefInt)
{
myRefInt = 66;
}
Console.WriteLine(number);
//輸出:0
int number;
Method(out number);
void Method(out int myRefInt)
{
myRefInt = 66;
}
Console.WriteLine(number);
//輸出:66
從上述out用法的表現來看,out和ref其實都可以允許通過引用來傳遞參數。那麼問題來了既然ref 、out的作用看起來一樣,爲什麼還定義了兩個關鍵字呢?
ref和out的區別
Stack Overflow的解釋:
意思就是:當你在使用ref傳遞參數的時候,ref修飾的參數必須要有值,但是out可以使用一個未賦值的變量作爲參數傳遞。下面我也用代碼做了驗證。
class RefAndOut
{
public static void OutDouble(out int outInt)
{
outInt = 2;
Console.WriteLine("outInt is:"+outInt);
}
public static void RefDouble(ref int parInt)
{
parInt *= 2;
Console.WriteLine("refInt is:"+parInt);
Console.ReadKey();
}
public static void NormalDouble(int IntPar)
{
IntPar = 1;
IntPar *= 2;
Console.WriteLine("normalInt is:" + IntPar);
Console.ReadKey();
}
static void Main(string[] args)
{
int refInt;
int outInt;
int normalInt;
OutDouble(out outInt);
RefDouble(ref refInt);
NormalDouble(normalInt);
}
}
這段代碼在兩處地方有錯誤:即在使用ref,和不使用修飾符的時候,必須要傳遞一個有值的參數。所以你看,ref和out幾乎就只有一個區別,那就是out可以使用未賦值的變量。
但是此處還有一個未解的地方,就是爲什麼Out不需要賦值呢?這也是這篇博客拖了一週的原因。。今天大概能解釋了。我們看下圖,不管有沒有對靜態變量outInt賦值,只要出使用out修飾符,就必須對out修飾的參數outIntPar賦值。
所以out應該是在方法內部做了分配地址的操作,然後把地址賦給外部的變量。但是ref的話是直接傳遞外部地址進方法。OK至此已經解釋清楚ref和out的區別了。
如果有錯誤的地方還請指出一同討論。