前言
一般程序員所擁有最“強”的兩件武器就是:復制和粘帖。String 這篇文章是想介紹大家一個小技巧。 我們知道,或者第一天學習C#的時候就認識string類型,然後很快就知道最簡單的拼裝string的寫法:
string s = string.Empty; s += "Bruce"; s += "Who?"; s += "a guy think sth different...";這種寫法實在是太簡單太美好了,因為相比C語言的 strcat 寫法,使用C#實在是太幸福了。而且不知道什麼時候還支持這種寫法:
s += "Bruce" + " Lee";(我實在不知道什麼時候開始支持以上寫法,記得.Net2.0是不能這樣寫的,如果是.Net1.1肯定不行,一定要加括號:
s += ("Bruce" + " Lee");) StringBuilder 然而,這種幸福感可能導致初學者不知道StringBuilder的存在,偶爾在其他人的文章上看到StringBuilder,可能也是不了解為什麼有“+=”不用,要寫上一堆 Append ...
StringBuilder sb = new StringBuilder(); sb.Append("Bruce"); sb.Append("Who?"); sb.Append("a guy think sth different...");你或許不相信,我估計在企業裡從事.Net工作一兩年的朋友,還是有人不知道StringBuilder的存在。特別在 Asp.Net 裡,不少朋友喜歡用C#拼裝一堆前台代碼,如Html語句或JavaScript,甚至SQL語句 … 他們無一例外都是使用“+=”來拼接,然後拍拍屁股就走人了,留下幾十行,甚至上百行這樣的語句。 我們應該知道,使用第一種方式來拼接字符串,無論是從時間或空間的性能來說,都遠不如使用StringBuilder。 好孩子看到這裡,可能就會趕快回去把自己那段“+=”全換上StringBuilder的 Append方法。先別急,畢竟由方式一向方式二轉換是很費時間的,絕對是苦力活,我現在要告訴大家怎麼以最快速使方式一的代碼性能上升到方式二。 StringJoiner 很簡單,把 string s 改成 StringJoiner s 就大功告成。即
StringJoiner s = string.Empty; s += "Bruce"; s += "Who?"; s += "a guy think sth different...";咋這麼簡單就提高性能?忽悠我? 當然不是忽悠大家,也不是玩魔術,文章末會有性能測試數據,有圖有真相。 現在讓我來揭開 StringJoiner 的面紗,最後你肯定會說:原來這麼簡單。 StringJoiner 其實是類似裝飾者模式,對外隱藏了StringBuilder ,就像魔術師喜歡把一堆道具藏到袖子,以忽悠觀眾那樣。
public class StringJoiner { protected StringBuilder Builder; public StringJoiner() { Builder = new StringBuilder(); } }(把Builder定義成protected ,期待某天可能需要繼承StringJoiner 來繼續“忽悠觀眾”) StringJoiner 是怎麼實現剛才的代碼? 1.隱式轉換 如:
StringJoiner s = string.Empty;的謎底是:
public static implicit operator StringJoiner(string value) { StringJoiner text = new StringJoiner(); text.Builder.Append(value); return text; }(新建一個對象,把賦值轉移到 StringBuilder 的Append方法) 2. 重載操作符 如:
s += "Bruce";的謎底是:
public static StringJoiner operator +(StringJoiner self, string value) { self.Builder.Append(value); return self; }(實現 StringJoiner 與 string 類型可以通過運算符“+”操作,同樣是把字符串交給StringBuilder 的Append方法) 為了更通用,如實現與其他類型連接:
s += 123; s += 0.314; s += c;因此,必須重載 StringJoiner + Object
public static StringJoiner operator +(StringJoiner self, object value) { self.Builder.Append(value); return self; }最後,為了讓 StringJoiner 的“忽悠”水平更上一層樓,StringJoiner 的對象必須能夠隱式轉換成 string 類型:
public static implicit operator string(StringJoiner value) { return value.ToString(); } public override string ToString() { return this.Builder.ToString(); }當然,到這一刻 StringJoiner 已經足夠了,更徹底的“忽悠”並不是本文的目的。 StringJoiner 並不是想替代string,更不是替代StringBuilder,反而我舉腳贊成使用StringBuilder。但如果你想重構一段由“string += ” 帶來的慘不忍睹的代碼時,用StringJoiner 吧。 性能測試 性能計數器:CodeTimer (XP版) 測試代碼(3種不同方法拼裝一萬次字符串,接著拼裝一萬次整數,並重復10次以上操作):
static void Main(string[] args) { CodeTimer.Time("", 1, () => { }); //通過 += 拼裝字符串 CodeTimer.Time("NormalString", 10, () => NormalString()); //StringJoiner 拼裝字符串 CodeTimer.Time(