2014-02-08 36 views
48

我對使用StringBuilder一流,有點糊塗:如何使用StringBuilder明智

一個string對象串聯操作總是創建從現有string和新數據的新對象。 A StringBuilder對象維護一個緩衝區以適應新數據的連接。如果空間可用,新數據將附加到緩衝區的末尾;否則,將分配一個新的更大的緩衝區,將原始緩衝區中的數據複製到新緩衝區中,然後將新數據附加到新緩衝區中。

但創建StringBuilder實例以避免創建新的String這一點在哪裏?這聽起來像是交易「一對一」。

static void Main(string[] args) 
{ 
    String foo = "123"; 
    using (StringBuilder sb = new StringBuilder(foo)) // also sb isn't disposable, so there will be error 
    { 
     sb.Append("456"); 
     foo = sb.ToString(); 
    } 

    Console.WriteLine(foo); 
    Console.ReadKey(); 
} 

爲什麼我不應該只使用

+= 

編輯:好吧,我現在知道如何重用的StringBuilder一個實例(仍然不知道這是否是正確的有代碼標準),但這不值得使用,只有一個string,不是嗎?

+5

http://www.dotnetperls.com/stringbuilder-performance與http://www.dotnetperls.com/st ring-concat – Steve

+1

@royB「字符串爭用本地使用stringbuilder(str1 + str2)」是什麼意思? String *連接*實際上*不*在內部使用StringBuilder。 –

回答

77

修改immutable結構如string小號必須通過複製的結構來完成,通過,消耗更多的內存,並減緩了應用程序的運行時間(也越來越多GC時間,等...)。

StringBuilder通過使用相同的可變對象進行操作來解決此問題。

但是:

在編譯時串聯一個string爲以下時:

string myString = "123"; 
myString += "234"; 
myString += "345"; 

它實際上將編譯成類似的東西:

string myString = string.Concat("123", "234", "345"); 

此功能比使用更快爲string s進入功能已知。

因此對於編譯時已知的string並置,你應該更喜歡string.Concat()

作爲未知數量的string像在以下情況下:

string myString = "123"; 
if (Console.ReadLine() == "a") 
{ 
    myString += "234"; 
} 
myString += "345"; 

現在,編譯器不能使用string.Concat()功能,但是,StringBuilder似乎是更有效的在時間和內存消耗只有當級聯使用6-7或更多strings完成。

壞實踐用法:

StringBuilder myString = new StringBuilder("123"); 
myString.Append("234"); 
myString.Append("345"); 

精細實踐使用(注意,if使用):

StringBuilder myString = new StringBuilder("123"); 
if (Console.ReadLine() == "a") 
{ 
    myString.Append("234"); 
} 
myString.Append("345"); 

最佳實踐使用(注意,while循環使用):

StringBuilder myString = new StringBuilder("123"); 
while (Console.ReadLine() == "a") 
{ 
    myString.Append("234"); //Average loop times 4~ or more 
} 
myString.Append("345"); 
+0

最後兩個例子不是完全一樣嗎? –

+1

@JaimieKnox注意'while' /'if'和註釋。 –

+3

啊謝謝你。我一定讀了100遍,但仍然錯過了。 –

1

原因是因爲strings是不可變的。當連接string時,您將創建一個新的string。所以,當你需要連接很多strings時,你創建了很多objects。這在內存方面沒有多少成本,因爲每個string都使用一次。但它確實爲GC提供了額外的工作。

StringBuilder但是每次都使用相同的object,但這樣做是以易用性爲代價的。

10

A string不可變類。你不能修改它,只能創建新的strings

所以,當你寫result += a;你有記憶三個獨立strings在這一點上:aresult舊值和新值。當然,如果您只連接了有限數量的strings,這絕對沒問題。如果你在for循環中這樣做,那麼迭代一個大集合就會成爲一個問題。

StringBuilder class在這些情況下提供了改進的性能。而不是創建新的strings來存儲連接的結果,它使用同一個對象。因此,如果您使用stringBuilder.Append(a);,則永遠不會具有「舊值result」的等效值。


這種記憶效率當然伴隨着價格。當只連接少數strings時,StringBuilder在速度方面通常效率較低,因爲與類不可變的類比,它具有更多開銷。


有一點要記住的是,當你需要的在中間串接着StringBuilder可以成爲自調用它.ToString()效率較低創建string的新副本。