string 是很特別的 是參考型別 但是使用起來跟實值型別一樣
就來聊聊string為何這樣的特殊吧
string的不變性意思就是指 每個string都是獨立的
你只要編輯過 就是產生另一個新string
舉例
var demo = "a";
demo = "a"+"b";
這樣 其實產生了兩個string 一個是a 一個是ab
然後a用不到了GC會去回收
所以才會有一些建議少用 + 字串 多用 string builder
建議在迴圈裡面組字串的話 用 string builder 是比較保險的
其實觀念就是這樣
來看點code
void Main()
{
var name1 = "Peter";
var name2A = "Pe";
var name2B = "ter";
var name2 = name2A + name2B;
var name3 = new string(new Char[] { 'P', 'e', 't', 'e', 'r' });
$"{name1} {name2} {name3}".Dump();
Object.ReferenceEquals(name1, name2).Dump("name1 Equal name2");
Object.ReferenceEquals(name2, name3).Dump("name2 Equal name3");
Object.ReferenceEquals(name1, name3).Dump("name1 Equal name3");
}
明明都是Peter字串的記憶體位置是完全不同的
如果只是這樣應該很好懂但錯了 因為這樣也太浪費記憶體了
所以net做了一件事情
String Pool 就是把一樣的字串 共用記憶體
前提是 編譯時 一樣的字串
看code
void Main()
{
var name1 = "Peter";
var name2 = "Peter";
$"{name1} {name2}".Dump();
Object.ReferenceEquals(name1, name2).Dump("name1 Equal name2");
}
雖然剛剛說過不變性 現在記憶體位置又是相等?!到底是怎
注意看程式碼 這次兩個都是寫死的字串 再編譯時就一樣了
上一個範例是執行時才產生出相同的Peter
這時候其實就是Peter這個字串進入了 String Pool
下次有遇到有人又要Peter 我就給你我String Pool裡面的Peter
你不用在去佔一塊記憶體了
也可以把字串加入到String Pool
使用String.Intern
void Main()
{
var name1 = "Peter";
var name2 = "Peter";
Object.ReferenceEquals(name1, name2).Dump("name1 Equal name2");
var name3A = "Pe";
var name3B = "ter";
var name3 = String.Intern(name3A + name3B);
Object.ReferenceEquals(name1, name3).Dump("name1 Equal name3");
}
這樣Peter都是指向同一個記憶體位置了
主廚由實戰面發現了這個問題加上圖文詳解值得一看
[食譜好菜] 從 C# 一個簡單的 lock string 修正了對 String Pool 的觀念
想不到天天都在用的string 如此複雜吧
參考
[.Net Concept]理解並善用String pool