關於字符串的駐留的機制,對於那些了解它的人肯定會認為很簡單,但是我相信會有很大一部分人對它存在迷惑。在開始關於字符串的駐留之前,先給出一個有趣的Sample:
Code Snip:
static void Main(string[] args)
{
string str1 = "ABCD1234";
string str2 = "ABCD1234";
string str3 = "ABCD";
string str4 = "1234";
string str5 = "ABCD" + "1234";
string str6 = "ABCD" + str4;
string str7 = str3 + str4;
Console.WriteLine("string str1 = "ABCD1234";");
Console.WriteLine("string str2 = "ABCD1234";");
Console.WriteLine("string str3 = "ABCD";");
Console.WriteLine("string str4 = "1234";");
Console.WriteLine("string str5 = "ABCD" + "1234";");
Console.WriteLine("string str6 = "ABCD" + str4;");
Console.WriteLine("string str7 = str3 + str4;");
Console.WriteLine("
object.ReferenceEquals(str1, str2) = {0}", object.ReferenceEquals(str1, str2));
Console.WriteLine("object.ReferenceEquals(str1, "ABCD1234") = {0}", object.ReferenceEquals(str1, "ABCD1234"));
Console.WriteLine("
object.ReferenceEquals(str1, str5) = {0}", object.ReferenceEquals(str1, str5));
Console.WriteLine("object.ReferenceEquals(str1, str6) = {0}", object.ReferenceEquals(str1, str6));
Console.WriteLine("object.ReferenceEquals(str1, str7) = {0}", object.ReferenceEquals(str1, str7));
Console.WriteLine("
object.ReferenceEquals(str1, string.Intern(str6)) = {0}", object.ReferenceEquals(str1, string.Intern(str6)));
Console.WriteLine("object.ReferenceEquals(str1, string.Intern(str7)) = {0}", object.ReferenceEquals(str1, string.Intern(str7)));
}
下邊是輸出的結果:
接下來我們來逐句地分析這段代碼:
首先我們創建了兩個完全相同的字符串(ABCD1234),並將他們分別賦予了兩個字符創變量——str1和str2。然後把它們傳給了object.ReferenceEquals。我們知道object.ReferenceEquals是用於確定兩個變量是否具有相同的引用——換句話說,當兩個變量引用的是同一塊托管推的內存快的時候,返回True,否則返回False。
string str1 = "ABCD1234";
string str2 = "ABCD1234";
object.ReferenceEquals(str1, str2)= True;
object.ReferenceEquals(str1, "ABCD1234")) = True;
令我們感到奇怪的是,當我們分別創建的引用類型兩個變量——string是引用類型。照理說CLR會在托管堆(Managed Heap)中為它們分配兩段內存快,他們不可能具有相同的引用才對,但是為什麼object.ReferenceEquals 方法會返回True呢。而對於第二個比較——一個字符串變量和一個和他具有相同內容的字符串("ABCD1234";)直接進行比較,按照我們對CLR內存的分配的一般理解,應該是CLR首先會在托管堆中為這段字符串("ABCD1234")分配內存快,然後把相對應的引用傳遞給object.ReferenceEquals方法(由於分配在托管堆的這段字符串並沒有被任何變量引用,所以當垃圾回收的時候會被回收掉),所以無論如何也不應該返回True。
我們先把問題留到最後,接著分析我們的Sample。上面們對字符串變量之間以及變量與字符串之間進行了比較,如果我們對一個字符串變量和一個動態創建的字符串(通過+Operator把兩個字符串連接起來)進行比較,結果又會如何呢?我們來看看下面的偽代碼演示:
string str3 = "ABCD";
string str4 = "1234";
string str5 = "ABCD" + "1234";
string str6 = "ABCD" + str4;
string str7 = str3 + str4;
object.ReferenceEquals(str1, str5) = True
object.ReferenceEquals(str1, str6) = False
object.ReferenceEquals(str1, str7)) = False
在上面的例子中,我們用三種不同的方式創建了3個字符串變量(str5,str6,str7)——string+string;string+variable;variable+variable。然後分別和我們已經創建的、和它們具有相同字符串“值”的變量(str1)作比較。同樣令我們感到奇怪的是第一個返回True,而後兩個則為False。帶著這些疑惑我們來看看對於string這一特殊的類型說采用的特殊的