先看例子:
class TestZhiYin
{
static void Main(string[] args)
{
int i = 100;
args ar=new args();
string str = "One";//特殊的引用類型
ChangeValueyin(ref i);
ChangeValueyin(ref ar);
ChangeStingyin( ref str);
Console.WriteLine(i);//200
Console.WriteLine(ar.j);//600
Console.WriteLine(str);//Two
// ChangeValuezhi(i);
// ChangeValuezhi(ar);
// ChangeStringzhi(str);
// Console.WriteLine(i);//100
// Console.WriteLine(ar.j);//600
// Console.WriteLine(str);//One
}
static void ChangeValueyin(ref int iVlaue)
{
iVlaue = 200;
Console.WriteLine(iVlaue);
}
static void ChangeValuezhi(int iVlaue)
{
iVlaue = 300;
Console.WriteLine(iVlaue);
}
static void ChangeValueyin(ref args ar)
{
ar.j=600;
Console.WriteLine(ar.j);
}
static void ChangeValuezhi(args ar)
{
ar.j=600;
Console.WriteLine(ar.j);
}
static void ChangeStingyin( ref string sValue)
{
sValue = "Two";
Console.WriteLine(sValue);
}
static void ChangeStringzhi(string sValue)
{
sValue = "Two";
Console.WriteLine(sValue);
}
}
public class args
{
public int j=5;
}
這裏先說明一下:無論是值類型,還是引用類型不加ref、out關鍵字都是按值傳遞的。值類型傳遞的是值本身的拷貝,引用類型傳遞的是引用本身的拷貝。對值拷貝的操作不會影響到原來的值;對引用拷貝的操作(拷貝引用和原來引用指向同一個對象)可以影響原來的對象,但是特例string除外。
加上ref、out就是按引用傳遞了(就是傳遞的真實內存地址),對於值類型來說就是值的內存地址,對於引用類型來說,就是這個引用的內存地址。這樣的操作,都會改變函數外變的量。
下面進行結果分析:
第一次執行(按地址傳參):
int i = 100;
args ar=new args();
string str = "One";//特殊的引用類型
ChangeValueyin(ref i);
ChangeValueyin(ref ar);
ChangeStingyin( ref str);
Console.WriteLine(i);//200
Console.WriteLine(ar.j);//600
Console.WriteLine(str);//Two
其結果對比:
i=100-----執行函數後i=200
ar.j=5-----執行函數後ar.j=600
str="One"-----執行函數後str="Two"
無論是值類型,還是引用類型,按地址傳遞都將改變其原來值。
第二次執行(按值傳參):
ChangeValuezhi(i);
ChangeValuezhi(ar);
ChangeStringzhi(str);
Console.WriteLine(i);//100
Console.WriteLine(ar.j);//600
Console.WriteLine(str);//One
其結果對比:
i=100-----執行函數後i=100
ar.j=5-----執行函數後ar.j=600
str="One"-----執行函數後str="One"
可以看出,當按值傳參的時候,i與ar.j執行函數後結果是不一樣的。
i沒有被改變,因爲傳遞的是i=100這個值的一個拷貝,對它的任何操作不會對原來的i=100有任何改變。
args類中j的值被改變了,因爲args是引用類型,當按值(這個值就是args引用的一個拷貝)傳遞args時,
傳遞的是args引用的拷貝,引用拷貝和原來的引用都指向同一個對象,所以j被改變了。
再看str定義的是string類型,string也是引用類型,爲什麼沒有像args一樣?
string是特殊的引用類型,它具有恆定性,也就是說,一個字符串創建以後,不能再對它進行任何更改
對它更改都會重新創建一個新的字符串
比如:string str="avb"執行object.ReferenceEquals(str,str.ToUpper())將得到false
如果按一般引用類型,對原有引用上的修改不會引起重新創建一個新的對象。
如果對一個字符進行頻繁的操作,這時你應該考慮用StringBuilder,StringBuilder維護的是一個字符串數組
對它的操作,會體現到它本身,而不是去創建另一個字符串對象,這樣比對string的操作節省了內存空間。
另外補充:
ref 參數傳入前必須被初始化,out不用,out需要在過程中對它初始化
可以通過ref和out來實現方法重載,但又不允許通過區分ref和out來實現方法重載
比如上面可以實現ChangeValueyin ref或者out的重載
ChangeValueyin(int iVlaue)
ChangeValueyin(ref int iVlaue)
這樣將不被允許
ChangeValueyin(out int iVlaue)
ChangeValueyin(ref int iVlaue)
僅代表個人觀點,如果認識有什麼不足還請指教!!!