先看一段代碼1:
{
StringBuilder sb = new StringBuilder( " 1 ");
test(sb);
Console.WriteLine(sb.ToString());
Console.Read();
}
static void test(StringBuilder sb)
{
sb = new StringBuilder( " 2 ");
}
錯誤的觀念:
程序輸出"2",因為StringBuilder是引用類型,函數內部sb變量重新指向了托管堆中的新對象,函數返回后,外部的sb變量也指向了這個新對象,因為是引用類型嗎,我傳的是引用。
在錯誤的觀念中,認為 “ref引用傳參” 僅對.net中的另一種基本類型——值類型有用。
這種錯誤觀念通常源於這樣的經驗,看代碼2:
{
StringBuilder sb = new StringBuilder( " 1 ");
test(sb);
Console.WriteLine(sb.ToString());
Console.Read();
}
static void test(StringBuilder sb)
{
sb.Append( " 2 ");
}
我們通常會很自豪的說:“看吧,程序輸出12,這就是引用類型的特點,如果換成值類型就不是了!”。我們得出的結論並沒有錯,實際上,這正是引用類型的特點!然而將這個觀念擴大到代碼1的情況,就錯了!
正確的理解:
程序正確的輸出是“1”,並沒有因為StringBuilder是引用類型,就應該輸出“2” 。如果要輸出“2”,需要加ref:
{
StringBuilder sb = new StringBuilder( " 1 ");
test(ref sb);
Console.WriteLine(sb.ToString());
Console.Read();
}
static void test( ref StringBuilder sb)
{
sb = new StringBuilder( " 2 ");
}
對於ref傳參,只要記住一點:對於值類型來說傳的是值的地址,對於引用類型來說傳的是地址的地址。
對於引用類型,同樣記住一點:引用類型本身的地址是一個值類型。就像我們學習c時,指針本身的地址就是一個int。
好吧,用c來理解c#果然有點拗!直觀的理解:引用類型對象本身不改變,只改變對象的屬性時,我們在操作同一個對象;
如果連對象本身都可能會改變,又要保證在操作同一個對象,就用ref傳引用類型的對象吧!
為什么不用string作測試呢?
因為string對象雖然是引用類型,但不能改變對象的屬性CharArray,每次返回的都是新對象(看起來像值類型,其實不是!)。
{
String s = " 1 "
test(s);
Console.WriteLine(s);
Console.Read();
}
static void test(String s)
{
s= " 2 ";
}
程序輸出"1",加 ref后輸出"2"。然而我沒法寫出代碼2了,看來string這個不可變引用類型並不適合作本文的測試,千萬不要認為string是什么混血兒。