看到这个标题是不是觉得很奇怪呢?字符串连接的性能,这个话题已经被谈了一遍又一遍,一次又一次,似乎已成定论,这又有什么好谈的呢?不过说来奇怪,根据我的实验结果在网上进行搜索,却找不到答案。因此,我现在和大家一起重新再作一次实验并观察结果。在文章最后我也会给出完整的代码,您可以自由地运行,修改,尝试,我们再一起进行交流。
说起字符串拼接,最简单的方式便是使用最普通的连接操作“+”,以及StringBuilder了。为此,我们准备一些测试代码:
private static readonly string STR = "0123456789"; private static string NormalConcat(int count) { var result = ""; for (int i = 0; i < count; i++) result += STR; return result; } private static string StringBuilder(int count) { var builder = new StringBuilder(); for (int i = 0; i < count; i++) builder.Append(STR); return builder.ToString(); }
两个方法都是将一个长度为10的字符串连接n次,形成一个很长的字符串。相信看到这两段代码您在心里可能已经有所答案了,不过别急,我们再准备一段代码。一直说StringBuilder在连接字符串的时候性能高,那是为什么呢?我们如果翻看《CLR via C#》,就会发现书中告诉我们说,在StringBuilder内部其实维护了一个类似于字符数组的结构,在不断添加字符串的过程中,这个数组会在需要的时候将容量加倍——这不就是List<T>的行为方式吗?那么我们自己来写一个CharListBuilder,也一起和StringBuilder比较一下性能:
public class CharListBuilder { private List<char> m_list = new List<char>(); public CharListBuilder Append(string s) { this.m_list.AddRange(s); return this; } public string ToString() { return new String(this.m_list.ToArray()); } } private static string CharListBuilder(int count) { var builder = new CharListBuilder(); for (int i = 0; i < count; i++) builder.Append(STR); return builder.ToString(); }
开始实验:
CodeTimer.Initialize(); for (int i = 2; i <= 1024; i *= 2) { CodeTimer.Time( String.Format("Normal Concat ({0})", i), 10000, () => NormalConcat(i)); CodeTimer.Time( String.Format("StringBuilder ({0})", i), 10000, () => StringBuilder(i)); CodeTimer.Time( String.Format("CharListBuilder ({0})", i), 10000, () => CharListBuilder(i)); }
结果如下:
http://blog.zhaojie.me/2009/11/string-concat-perf-1-benchmark.html