StringJoiner 拯救那些性能低下的字符串拼装代码
前言
一般程序员所拥有最“强”的两件武器就是:复制和粘帖。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(补充:软件开发 , C# ,