C#实现方便又高效的字符串拼接类StringJoiner

本文介绍了一种在C#中优化字符串拼接的方法——使用StringJoiner类,该类模仿StringBuilder的行为,通过简单的代码替换即可显著提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

一般程序员所拥有最 “强”的两件武器就是:复制和粘帖。
  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("StringJoiner", 10, () => StringJoiner());

    //StringBuilder 拼装字符串
    CodeTimer.Time("StringBuilder", 10, () => StringBuilder());

    Console.WriteLine("continue...");
    Console.Read();
}

//拼装字符串长度
const int stringLength = 10000;

static void NormalString()
{
    string s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += "A";//拼装字符串
    s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += 1;//拼装整数
    string result = s;
}

static void StringJoiner()
{
    StringJoiner s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += "A";
    s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += 1;
    string result = s;
}

static void StringBuilder()
{
    StringBuilder s = new StringBuilder(string.Empty);
    for (int i = 0; i < stringLength; i++)
        s.Append("A");
    s = new StringBuilder(string.Empty);
    for (int i = 0; i < stringLength; i++)
        s.Append(1);
    string result = s.ToString();
}
 
其中一次测试结果:

 

NormalString
        Time Elapsed:            667ms
        Time Elapsed (one time):66ms
        CPU time:               671,875,000ns
        CPU time (one time):    67,187,500ns
        Gen 0:                   1908
        Gen 1:                  0
        Gen 2:                  0
 
StringJoiner
        Time Elapsed:            19ms
        Time Elapsed (one time):1ms
        CPU time:               15,625,000ns
        CPU time (one time):    1,562,500ns
        Gen 0:                   3
        Gen 1:                  0
        Gen 2:                  0
 
StringBuilder
        Time Elapsed:            19ms
        Time Elapsed (one time):1ms
        CPU time:               15,625,000ns
        CPU time (one time):    1,562,500ns
        Gen 0:                   3
        Gen 1:                  0
        Gen 2:                  0

 
从上图可以看到, StringJoiner 和  StringBuilder 性能持平,而它们都远远比第一种方法领先。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值